Compare commits
649 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a795fc4310 | ||
|
|
790b743e42 | ||
|
|
21aeded2ea | ||
|
|
baf6d6bd29 | ||
|
|
2e213a8692 | ||
|
|
455cccebb5 | ||
|
|
9e602394cf | ||
|
|
46ebd49936 | ||
|
|
fcac750ad7 | ||
|
|
8cd3acd205 | ||
|
|
bc95a028ce | ||
|
|
5fb457d331 | ||
|
|
454c11a12c | ||
|
|
3ac9a418e6 | ||
|
|
c98de5988e | ||
|
|
ca5df588b7 | ||
|
|
08a41691af | ||
|
|
665f272a0e | ||
|
|
2591e3ab67 | ||
|
|
44df9b3be8 | ||
|
|
40ddfa8def | ||
|
|
cc27c552af | ||
|
|
7f248da0b3 | ||
|
|
79a0002594 | ||
|
|
a6c015bcc5 | ||
|
|
692d98cb55 | ||
|
|
d9ddc184cb | ||
|
|
e424d06026 | ||
|
|
f9821e5f80 | ||
|
|
5bd53dc093 | ||
|
|
204834872e | ||
|
|
a24049aa17 | ||
|
|
9cb9e9e7b6 | ||
|
|
3e7a766d12 | ||
|
|
02debdc28b | ||
|
|
e104fe3021 | ||
|
|
dda40537cc | ||
|
|
217269467c | ||
|
|
5f193680c9 | ||
|
|
c0ef713c0b | ||
|
|
3533aa391a | ||
|
|
ec90365427 | ||
|
|
78f7a9ba06 | ||
|
|
7793dd8b3e | ||
|
|
76866f78f0 | ||
|
|
8e3ecb4c25 | ||
|
|
1b9b2ac4c9 | ||
|
|
489f14b88f | ||
|
|
8f09c82763 | ||
|
|
2b8cda40a2 | ||
|
|
4656d67fcf | ||
|
|
e7dd67deaa | ||
|
|
b9c3219094 | ||
|
|
f55a995c0a | ||
|
|
ee378a128c | ||
|
|
c1f083d19f | ||
|
|
2ff0f97295 | ||
|
|
dd3b51d0b7 | ||
|
|
853acfda2c | ||
|
|
c756be54a1 | ||
|
|
3bbf334f99 | ||
|
|
c6c8b7da6a | ||
|
|
8a30d3ed42 | ||
|
|
a5a6b864a5 | ||
|
|
97b7320939 | ||
|
|
5c11bcb2c6 | ||
|
|
3888584b58 | ||
|
|
531a9c0bc8 | ||
|
|
84f8048e0a | ||
|
|
fdf96b0b63 | ||
|
|
86ddfe2c9f | ||
|
|
115ae93073 | ||
|
|
aa65cada6f | ||
|
|
ad9cdf3fa8 | ||
|
|
5c0035f4c3 | ||
|
|
37b4c67ead | ||
|
|
63998f4a23 | ||
|
|
efeec13794 | ||
|
|
6c49e5c86a | ||
|
|
ec57392424 | ||
|
|
8713aa7fd3 | ||
|
|
627811f28d | ||
|
|
3f743b4f61 | ||
|
|
d676b5a68d | ||
|
|
a6dfab5fbf | ||
|
|
b8bc110d33 | ||
|
|
597fd2c6d1 | ||
|
|
ab0bc3e927 | ||
|
|
e28373dae1 | ||
|
|
1bc57f159c | ||
|
|
6a8019c7a0 | ||
|
|
9b0dc5a849 | ||
|
|
283e1b0790 | ||
|
|
fc05a4bb78 | ||
|
|
88b32e317a | ||
|
|
6c61a70d58 | ||
|
|
5df3ebae22 | ||
|
|
ad252476ce | ||
|
|
8e5f6a3a96 | ||
|
|
9ff209bd32 | ||
|
|
505e61475d | ||
|
|
2c137a0eec | ||
|
|
b65ae89be6 | ||
|
|
432884a2af | ||
|
|
6878498b2e | ||
|
|
4d5332fef7 | ||
|
|
50a149b662 | ||
|
|
930838d676 | ||
|
|
f6c952ffb0 | ||
|
|
f6db530de2 | ||
|
|
db45f08905 | ||
|
|
516d53f9bf | ||
|
|
c7e1adf638 | ||
|
|
31147975c7 | ||
|
|
b9deec1487 | ||
|
|
de57208bab | ||
|
|
07e966c640 | ||
|
|
56982effcd | ||
|
|
8a52b0fbd6 | ||
|
|
2190a1b6fd | ||
|
|
c18c2ea9d4 | ||
|
|
5fce1118f6 | ||
|
|
64f64b9e31 | ||
|
|
b4ac527638 | ||
|
|
352f3af737 | ||
|
|
c7c221ad5e | ||
|
|
74adbae7ed | ||
|
|
8a5402932c | ||
|
|
e565f9bf72 | ||
|
|
942b86c647 | ||
|
|
1042310038 | ||
|
|
d0c261b9cd | ||
|
|
61396cbb15 | ||
|
|
87c6230ef2 | ||
|
|
347ad94a43 | ||
|
|
f1389cdba0 | ||
|
|
5399ddf6ac | ||
|
|
a724dc1207 | ||
|
|
c6af38f7dc | ||
|
|
4d0008186b | ||
|
|
df3df6697e | ||
|
|
13ff7b9088 | ||
|
|
196d252fec | ||
|
|
53dfdc440d | ||
|
|
988a99efb7 | ||
|
|
17da230d72 | ||
|
|
c8cdfc8885 | ||
|
|
0b00842c50 | ||
|
|
17e405a39e | ||
|
|
51bd3455cc | ||
|
|
e292af75ad | ||
|
|
ef4566eb95 | ||
|
|
e7d1ffb7ae | ||
|
|
4fded3ada3 | ||
|
|
dc5ca76d05 | ||
|
|
37bdd525ea | ||
|
|
3f03806455 | ||
|
|
ff7bb1f303 | ||
|
|
5fe1de170d | ||
|
|
72913ccece | ||
|
|
a6207e7edf | ||
|
|
2972ac6328 | ||
|
|
d90550438f | ||
|
|
aa0f08cba3 | ||
|
|
a1b39d4fbc | ||
|
|
091a160db3 | ||
|
|
03f6336ac5 | ||
|
|
24c4cfe586 | ||
|
|
ca0c858e0f | ||
|
|
2be9a0bdba | ||
|
|
d333a44e11 | ||
|
|
e8e855a36c | ||
|
|
09719a4ad3 | ||
|
|
c9e542d6d5 | ||
|
|
a32ce56295 | ||
|
|
279c8c14cc | ||
|
|
49bc2c2204 | ||
|
|
c036c945bd | ||
|
|
2e2cce9fcb | ||
|
|
7f33798789 | ||
|
|
e299433e6e | ||
|
|
c82cb67bb6 | ||
|
|
075e11a7e1 | ||
|
|
2b2c968a97 | ||
|
|
bffdb39c02 | ||
|
|
3dabd73e95 | ||
|
|
8ed30e7eda | ||
|
|
7e4297d9bf | ||
|
|
99e634711e | ||
|
|
07f370d6d2 | ||
|
|
d2dfb4c8df | ||
|
|
64ee01d9fe | ||
|
|
a8d5ab035d | ||
|
|
f58c6807d0 | ||
|
|
ca66b47014 | ||
|
|
290781e734 | ||
|
|
d403e10018 | ||
|
|
161a0e07f9 | ||
|
|
eb9b0c85a9 | ||
|
|
c7f7b96405 | ||
|
|
c5dff96f57 | ||
|
|
ff418ad55f | ||
|
|
6b0da0a568 | ||
|
|
56151982a7 | ||
|
|
c8185050f6 | ||
|
|
ed20b009a5 | ||
|
|
bf0bcf2f72 | ||
|
|
d81e80f273 | ||
|
|
6afed0e035 | ||
|
|
0a39e7b02f | ||
|
|
01a45f3085 | ||
|
|
c61764cd8d | ||
|
|
ce20f5d0a2 | ||
|
|
ffa9210286 | ||
|
|
025ead4fa3 | ||
|
|
82de03101b | ||
|
|
eae071f9b8 | ||
|
|
aadad482c4 | ||
|
|
cb8b98f707 | ||
|
|
603a888e2e | ||
|
|
9e3083cc5d | ||
|
|
ab9f2c0a66 | ||
|
|
e84888c27e | ||
|
|
4dfc91db0a | ||
|
|
5705df96f3 | ||
|
|
9ac0cf1406 | ||
|
|
71170a1c5d | ||
|
|
353978f115 | ||
|
|
e89065aafc | ||
|
|
ff35ccbaec | ||
|
|
529d5b0535 | ||
|
|
15ecb19c65 | ||
|
|
a64b32d12c | ||
|
|
f53ac25d90 | ||
|
|
de1d06528e | ||
|
|
ea227e09fa | ||
|
|
46cbd6dfd2 | ||
|
|
a61e6efdd4 | ||
|
|
6536d71566 | ||
|
|
d92412175c | ||
|
|
a3b7f9a739 | ||
|
|
5367a23112 | ||
|
|
3614f5b620 | ||
|
|
eac7954570 | ||
|
|
7d08da22b2 | ||
|
|
756acf1395 | ||
|
|
a2a03c6b52 | ||
|
|
8e63a84152 | ||
|
|
38b3197912 | ||
|
|
1d4576c7fd | ||
|
|
29a4dee91b | ||
|
|
9e166774ef | ||
|
|
dd40df4b37 | ||
|
|
afd07562b4 | ||
|
|
81a6d821c0 | ||
|
|
858ab252a6 | ||
|
|
a56e2bb577 | ||
|
|
27980cf7c7 | ||
|
|
5a7bcf32ea | ||
|
|
773423069b | ||
|
|
1e6773deb5 | ||
|
|
a95d37d610 | ||
|
|
bdf72eca70 | ||
|
|
3acb2a56a2 | ||
|
|
2f0e9d0681 | ||
|
|
bfa7eb0c19 | ||
|
|
27d71fb10f | ||
|
|
eeb1ecd2df | ||
|
|
f21b5768a5 | ||
|
|
ba08883623 | ||
|
|
b1587950c6 | ||
|
|
b473ed7cb7 | ||
|
|
2978c8adfe | ||
|
|
1f0111256b | ||
|
|
346b980a1d | ||
|
|
8000791e17 | ||
|
|
66077ea6d7 | ||
|
|
3d10a8f86a | ||
|
|
ebae9880dc | ||
|
|
2e72c16964 | ||
|
|
6ebaea395d | ||
|
|
257ee9928f | ||
|
|
2ac9f5918a | ||
|
|
9c4767bb68 | ||
|
|
cbd82988a8 | ||
|
|
d0a9445dfc | ||
|
|
cd6a9bf9a8 | ||
|
|
8afead4e39 | ||
|
|
f279471858 | ||
|
|
61fe518710 | ||
|
|
b774a59db2 | ||
|
|
63a1f52482 | ||
|
|
ab5ea5948b | ||
|
|
a8fd0fcd19 | ||
|
|
6098d55b57 | ||
|
|
9ba2f80e3a | ||
|
|
3acf71f253 | ||
|
|
ad51597bf5 | ||
|
|
60057eee6a | ||
|
|
3cfd0ba1f8 | ||
|
|
dec386840a | ||
|
|
355b9be3ff | ||
|
|
57627367f5 | ||
|
|
a5a812d3f4 | ||
|
|
5426273cf8 | ||
|
|
d9bab319e3 | ||
|
|
77862cdf9b | ||
|
|
b8d68ee359 | ||
|
|
307e434f91 | ||
|
|
f60b2eb8af | ||
|
|
9da1aa1421 | ||
|
|
4d3964daeb | ||
|
|
b80f9d3517 | ||
|
|
46981f73a9 | ||
|
|
9b6394627b | ||
|
|
3a34331cc2 | ||
|
|
95fe10b312 | ||
|
|
f8d4303531 | ||
|
|
7d49f75682 | ||
|
|
a84a8e1a6e | ||
|
|
1fc2181937 | ||
|
|
7411f01fb5 | ||
|
|
2c9c598dd7 | ||
|
|
3c00a3b1d0 | ||
|
|
660cdb575a | ||
|
|
f20876a028 | ||
|
|
b31866cf32 | ||
|
|
bde27c3880 | ||
|
|
80cb613888 | ||
|
|
23966b1103 | ||
|
|
2fd897064a | ||
|
|
846298210a | ||
|
|
f22e98ccca | ||
|
|
5cb6d10e3d | ||
|
|
5b4dd74503 | ||
|
|
cd3cec5d48 | ||
|
|
621888d6d4 | ||
|
|
3e7fcaf764 | ||
|
|
8fb44df59b | ||
|
|
5b205d6e4a | ||
|
|
dc98ef8b57 | ||
|
|
f9ae242792 | ||
|
|
438640d5b8 | ||
|
|
078b755fb6 | ||
|
|
501e01fe23 | ||
|
|
ce992fc205 | ||
|
|
8609dedafd | ||
|
|
66f124b397 | ||
|
|
21cf439210 | ||
|
|
91a7d20923 | ||
|
|
f49c2138de | ||
|
|
774853af7a | ||
|
|
7e30a4a3d4 | ||
|
|
b179731359 | ||
|
|
d6409d7152 | ||
|
|
eaeefafe39 | ||
|
|
59974edf80 | ||
|
|
37f914d1cc | ||
|
|
da92fd705b | ||
|
|
00505b8af8 | ||
|
|
22a3bba6ab | ||
|
|
b6b3cbcb9a | ||
|
|
de97048424 | ||
|
|
02471e6d60 | ||
|
|
edf58ee897 | ||
|
|
5ecfd278d4 | ||
|
|
3327179270 | ||
|
|
98462e8dca | ||
|
|
2f515164b3 | ||
|
|
3c8ceebedc | ||
|
|
26fe93dfc0 | ||
|
|
9113a826ce | ||
|
|
eca1baf53e | ||
|
|
6b3b8e6204 | ||
|
|
194a4f3adb | ||
|
|
054f27083b | ||
|
|
168d1dc678 | ||
|
|
8cc5c62665 | ||
|
|
82c874afb5 | ||
|
|
1afd0381c1 | ||
|
|
5f5589f1f1 | ||
|
|
1cee408113 | ||
|
|
92854b9e84 | ||
|
|
a4c5817b54 | ||
|
|
6c82680066 | ||
|
|
6135bc716e | ||
|
|
1639ea7552 | ||
|
|
bea8c89d9f | ||
|
|
fe1618d1d8 | ||
|
|
30250e1afa | ||
|
|
16f02e2544 | ||
|
|
123f4a3931 | ||
|
|
ce5fb78bcd | ||
|
|
2ccd053b0a | ||
|
|
3422ccef15 | ||
|
|
630663ec83 | ||
|
|
37c6bf3a3f | ||
|
|
1c2963a1e0 | ||
|
|
50a5b0f7db | ||
|
|
df933bb928 | ||
|
|
aa85108f1a | ||
|
|
c778a28f2b | ||
|
|
48142721ac | ||
|
|
826e3ebc5e | ||
|
|
0f31259c97 | ||
|
|
881d7fa5ee | ||
|
|
d479425333 | ||
|
|
cb944bcfb2 | ||
|
|
745683f2a8 | ||
|
|
e019935545 | ||
|
|
9601477bba | ||
|
|
0702ca3fc9 | ||
|
|
d9a9ae7e72 | ||
|
|
76eba3d638 | ||
|
|
69a448b4c1 | ||
|
|
a8d9a64f79 | ||
|
|
1546727612 | ||
|
|
dfdcc05d3e | ||
|
|
12941a107d | ||
|
|
a94d46e005 | ||
|
|
acb777c236 | ||
|
|
7e87cc1923 | ||
|
|
1ad23f4ed8 | ||
|
|
1bcba17f76 | ||
|
|
cb871f6a88 | ||
|
|
6d2c296a7d | ||
|
|
3434a1f5a6 | ||
|
|
f9c45d95e1 | ||
|
|
0bd051a7a9 | ||
|
|
d4789463ad | ||
|
|
7190a25550 | ||
|
|
04bc8308ac | ||
|
|
68c67fbd32 | ||
|
|
50fd8926d6 | ||
|
|
7e1e61f8af | ||
|
|
ee066d7859 | ||
|
|
54a48f9493 | ||
|
|
70fc0789d6 | ||
|
|
66cd75dce8 | ||
|
|
8b3b6a471b | ||
|
|
e707fcda05 | ||
|
|
a3574acabd | ||
|
|
f36db182f1 | ||
|
|
59e492b2a6 | ||
|
|
6380063978 | ||
|
|
2686873163 | ||
|
|
b2ef26600c | ||
|
|
e94fdcad32 | ||
|
|
2e423b101b | ||
|
|
91677a41d4 | ||
|
|
b747d0273c | ||
|
|
45fb612793 | ||
|
|
db081d3197 | ||
|
|
423eaa5462 | ||
|
|
f38dde160e | ||
|
|
782eb29aac | ||
|
|
5810c5544a | ||
|
|
b6eb581192 | ||
|
|
54171e566a | ||
|
|
b7a44ab11f | ||
|
|
4ea60d3431 | ||
|
|
9840ebfe33 | ||
|
|
af2b726a38 | ||
|
|
d425a1b2c0 | ||
|
|
687b0ac3bd | ||
|
|
3978dd9b07 | ||
|
|
d9f78b9d5c | ||
|
|
81e638a7e0 | ||
|
|
6dc906a604 | ||
|
|
005db4d0e8 | ||
|
|
41127da7d9 | ||
|
|
3111b8d395 | ||
|
|
89f2647ead | ||
|
|
084a432741 | ||
|
|
1f071d1608 | ||
|
|
3f75d0df56 | ||
|
|
ba108fe23a | ||
|
|
ab736cf975 | ||
|
|
c36239772e | ||
|
|
286090d58a | ||
|
|
69fda864db | ||
|
|
2709c5d332 | ||
|
|
da5fdd54bd | ||
|
|
92e7453c31 | ||
|
|
a59e1a2015 | ||
|
|
838eb845d4 | ||
|
|
f69fdc634a | ||
|
|
9c0e7272ff | ||
|
|
515afdc5ae | ||
|
|
f32fa485e0 | ||
|
|
a5187801b4 | ||
|
|
6cb11d6a61 | ||
|
|
1e91ca5eda | ||
|
|
210727ea0e | ||
|
|
f429585447 | ||
|
|
759a3f17cc | ||
|
|
de7d1c2baa | ||
|
|
8223011c3d | ||
|
|
53684d6fbb | ||
|
|
31cefd7dd0 | ||
|
|
993a8f83ff | ||
|
|
fd1e00986c | ||
|
|
62028d1273 | ||
|
|
240ae25a90 | ||
|
|
2bd242a164 | ||
|
|
4b87684611 | ||
|
|
3cd2a2a0f9 | ||
|
|
dc129eeb7d | ||
|
|
fb3f426688 | ||
|
|
f33ebbcce0 | ||
|
|
86922df61a | ||
|
|
2916ab502e | ||
|
|
9c24fcec0d | ||
|
|
8258997f3e | ||
|
|
ef714c3903 | ||
|
|
76c0874f0e | ||
|
|
9166f734c9 | ||
|
|
368421a498 | ||
|
|
c8d8c68b95 | ||
|
|
e68cd3c47f | ||
|
|
1732d7e707 | ||
|
|
da0d778b25 | ||
|
|
b8bd0cc63a | ||
|
|
5150e13121 | ||
|
|
b2f784eeff | ||
|
|
ad98284caf | ||
|
|
6915ea70ca | ||
|
|
26eb99d4a7 | ||
|
|
e1eb1be781 | ||
|
|
b536e191b1 | ||
|
|
f1b475b966 | ||
|
|
23a61d400d | ||
|
|
4ae8308663 | ||
|
|
c3d6343edb | ||
|
|
1059d2ddbd | ||
|
|
10ecc27bb5 | ||
|
|
0c3c540051 | ||
|
|
c44dba5e92 | ||
|
|
82da7d0b24 | ||
|
|
4dd522eda4 | ||
|
|
bbe300e847 | ||
|
|
dd667e5b4a | ||
|
|
6f013de8e4 | ||
|
|
96a6289911 | ||
|
|
e0970fc69d | ||
|
|
5cafc7bb37 | ||
|
|
2b755c0497 | ||
|
|
e3beae244d | ||
|
|
c2ec7be719 | ||
|
|
ed5d9132d3 | ||
|
|
8654db534b | ||
|
|
e20299eb94 | ||
|
|
1f65907f70 | ||
|
|
6a55c09328 | ||
|
|
9734e4d859 | ||
|
|
4f93bc5721 | ||
|
|
73dc0b1cfa | ||
|
|
e31979002f | ||
|
|
4be1e527fc | ||
|
|
45332b3202 | ||
|
|
cb0258cb58 | ||
|
|
f3d80f28fd | ||
|
|
4b73ee3d41 | ||
|
|
e0e2e0c2fb | ||
|
|
f2b977c941 | ||
|
|
9fe10fd9a2 | ||
|
|
6b444d280a | ||
|
|
10c2acf410 | ||
|
|
6bb5908aba | ||
|
|
f54b24b4da | ||
|
|
ef3c548c98 | ||
|
|
820690a073 | ||
|
|
63cf4f0045 | ||
|
|
deecbdd124 | ||
|
|
07f790dda0 | ||
|
|
a91b1ecf1f | ||
|
|
4f75dd30fe | ||
|
|
629ee3e33f | ||
|
|
54e06d26bc | ||
|
|
dda26b7a3f | ||
|
|
e86a17980b | ||
|
|
23068450ed | ||
|
|
3924370b3e | ||
|
|
f57ac978ae | ||
|
|
e68ad7331f | ||
|
|
9b5fb4bde1 | ||
|
|
a8f1fb5148 | ||
|
|
65185ecb77 | ||
|
|
14a68f24e4 | ||
|
|
16a93c2b7e | ||
|
|
925690fb00 | ||
|
|
dc279bc335 | ||
|
|
d1d759e86f | ||
|
|
82a30fbd25 | ||
|
|
12fea29f48 | ||
|
|
b602f7c03f | ||
|
|
a20ab981a7 | ||
|
|
9ae08cecf2 | ||
|
|
c9cd7b4344 | ||
|
|
24b587762a | ||
|
|
18a2fb38d1 | ||
|
|
5f47cdb763 | ||
|
|
e5a18b6e4c | ||
|
|
519976eb0b | ||
|
|
b630fbc641 | ||
|
|
2369a22d23 | ||
|
|
124d9ff269 | ||
|
|
1c95ac7f07 | ||
|
|
54169fe22b | ||
|
|
4707b78c1f | ||
|
|
95d91efe52 | ||
|
|
fc0c7f536b | ||
|
|
80f1cfc72d | ||
|
|
628012fb49 | ||
|
|
a29498e911 | ||
|
|
3d460b5862 | ||
|
|
4acb2a5d92 | ||
|
|
47c800b78b | ||
|
|
a20da8036f | ||
|
|
7897118fbd | ||
|
|
0246e09595 | ||
|
|
72ad37456a | ||
|
|
83ec0a6c76 | ||
|
|
63f77b0dc5 | ||
|
|
798d2e0e6b | ||
|
|
fd098b5440 | ||
|
|
11d30e409c | ||
|
|
6cb5ae246d | ||
|
|
60c76ba854 | ||
|
|
ebf7b32408 | ||
|
|
f343459236 | ||
|
|
d2a57864f0 | ||
|
|
8a07f281ff | ||
|
|
b7b721abd5 | ||
|
|
45f1e386cc | ||
|
|
3c3e8a6c31 | ||
|
|
ec99b48605 | ||
|
|
da9e599e8f | ||
|
|
b1d3fa3f42 | ||
|
|
7954672ef8 | ||
|
|
20a6039bd0 | ||
|
|
d7fe61bc3d | ||
|
|
b10406896a | ||
|
|
1f135e0721 | ||
|
|
e1bdc9ce33 | ||
|
|
e3654bb472 | ||
|
|
6418d6bcff | ||
|
|
9bf7c5013e | ||
|
|
1797e78ebd |
@@ -15,43 +15,6 @@
|
||||
"design"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "NBTX",
|
||||
"name": "John Harker",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/43181178?v=4",
|
||||
"profile": "https://github.com/NBTX",
|
||||
"contributions": [
|
||||
"code",
|
||||
"design"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "larouxn",
|
||||
"name": "Nicholas La Roux",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/1557529?v=4",
|
||||
"profile": "https://nicholaslaroux.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "yubathom",
|
||||
"name": "Thomas Yuba",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/4117768?v=4",
|
||||
"profile": "https://github.com/yubathom",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "nickpalenchar",
|
||||
"name": "Nick Palenchar",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/7539781?v=4",
|
||||
"profile": "http://www.linkedin.com/in/nickpalenchar",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AndrewBastin",
|
||||
"name": "Andrew Bastin",
|
||||
@@ -61,82 +24,10 @@
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "vlad0337187",
|
||||
"name": "Vladislav",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/12682937?v=4",
|
||||
"profile": "https://github.com/vlad0337187",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "izerozlu",
|
||||
"name": "izerozlu",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/17386157?v=4",
|
||||
"profile": "https://github.com/izerozlu",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "JacobAnavisca",
|
||||
"name": "Jacob Anavisca",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/21232366?v=4",
|
||||
"profile": "https://github.com/JacobAnavisca",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "nityanandagohain",
|
||||
"name": "Nityananda Gohain",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/26831659?v=4",
|
||||
"profile": "http://nityanandagohain.github.io",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "hosseinnedaee",
|
||||
"name": "Hossein Nedaee",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/42691357?v=4",
|
||||
"profile": "https://github.com/hosseinnedaee",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jamesgeorge007",
|
||||
"name": "James George",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/25279263?v=4",
|
||||
"profile": "https://ghuser.io/jamesgeorge007",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dmitryyankowski",
|
||||
"name": "Dmitry Yankowski",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/20114263?v=4",
|
||||
"profile": "https://dmitryyankowski.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sboulema",
|
||||
"name": "Samir Boulema",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/1820661?v=4",
|
||||
"profile": "http://www.sboulema.nl",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
"projectName": "postwoman",
|
||||
"projectOwner": "liyasthomas",
|
||||
"projectName": "hoppscotch",
|
||||
"projectOwner": "hoppscotch",
|
||||
"repoType": "github",
|
||||
"repoHost": "https://github.com",
|
||||
"skipCi": true
|
||||
|
||||
@@ -30,7 +30,7 @@ coverage
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
@@ -97,8 +97,8 @@ sw.*
|
||||
# Vim swap files
|
||||
*.swp
|
||||
|
||||
# Postwoman build data
|
||||
.postwoman
|
||||
# Build data
|
||||
.hoppscotch
|
||||
|
||||
# File explorer
|
||||
.directory
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# https://editorconfig.org
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
charset = utf-8
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
29
.env.example
@@ -1,15 +1,18 @@
|
||||
# Google Analytics
|
||||
GA_ID=UA-XXXXXXXX-X
|
||||
# Google Analytics ID
|
||||
GA_ID=UA-61422507-4
|
||||
|
||||
# Google Tag Manager
|
||||
GTM_ID=GTM-XXXXXXX
|
||||
# Google Tag Manager ID
|
||||
GTM_ID=GTM-NMKVBMV
|
||||
|
||||
# Firebase
|
||||
API_KEY=api-key
|
||||
AUTH_DOMAIN=project-id.firebaseapp.com
|
||||
DATABASE_URL=https://project-id.firebaseio.com
|
||||
PROJECT_ID=project-id
|
||||
STORAGE_BUCKET=project-id.appspot.com
|
||||
MESSAGING_SENDER_ID=sender-id
|
||||
APP_ID=app-id
|
||||
MEASUREMENT_ID=G-measurement-id
|
||||
# Firebase config
|
||||
API_KEY=AIzaSyCMsFreESs58-hRxTtiqQrIcimh4i1wbsM
|
||||
AUTH_DOMAIN=postwoman-api.firebaseapp.com
|
||||
DATABASE_URL=https://postwoman-api.firebaseio.com
|
||||
PROJECT_ID=postwoman-api
|
||||
STORAGE_BUCKET=postwoman-api.appspot.com
|
||||
MESSAGING_SENDER_ID=421993993223
|
||||
APP_ID=1:421993993223:web:ec0baa8ee8c02ffa1fc6a2
|
||||
MEASUREMENT_ID=G-ERJ6025CEB
|
||||
|
||||
# Base URL
|
||||
BASE_URL=https://hoppscotch.io
|
||||
|
||||
49
.eslintrc.js
Normal file
@@ -0,0 +1,49 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
parserOptions: {
|
||||
sourceType: "module",
|
||||
requireConfigFile: false,
|
||||
},
|
||||
extends: [
|
||||
"@nuxtjs",
|
||||
"@nuxtjs/eslint-config-typescript",
|
||||
"prettier/prettier",
|
||||
"eslint:recommended",
|
||||
"plugin:vue/recommended",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:nuxt/recommended",
|
||||
],
|
||||
plugins: ["vue", "prettier"],
|
||||
// add your custom rules here
|
||||
rules: {
|
||||
semi: [2, "never"],
|
||||
"no-console": process.env.NODE_ENV === "production" ? "error" : "off",
|
||||
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
|
||||
"vue/max-attributes-per-line": "off",
|
||||
"vue/component-name-in-template-casing": ["error", "PascalCase"],
|
||||
"vue/html-self-closing": [
|
||||
"error",
|
||||
{
|
||||
html: {
|
||||
normal: "never",
|
||||
void: "always",
|
||||
},
|
||||
},
|
||||
],
|
||||
"vue/singleline-html-element-content-newline": "off",
|
||||
"vue/multiline-html-element-content-newline": "off",
|
||||
"vue/require-default-prop": "warn",
|
||||
"vue/require-prop-types": "warn",
|
||||
"prettier/prettier": ["warn", { semi: false }],
|
||||
"import/no-named-as-default": "off",
|
||||
"no-undef": "off",
|
||||
},
|
||||
globals: {
|
||||
$nuxt: true,
|
||||
},
|
||||
}
|
||||
@@ -1,14 +1,5 @@
|
||||
{
|
||||
"projects": {
|
||||
"default": "postwoman-api"
|
||||
},
|
||||
"targets": {
|
||||
"postwoman-api": {
|
||||
"hosting": {
|
||||
"postwoman": [
|
||||
"postwoman"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
4
.github/FUNDING.yml
vendored
@@ -1,4 +1,4 @@
|
||||
github: postwoman-io
|
||||
open_collective: postwoman
|
||||
github: hoppscotch
|
||||
open_collective: hoppscotch
|
||||
patreon: liyasthomas
|
||||
custom: https://www.paypal.me/liyascthomas
|
||||
|
||||
2
.github/dependabot.yml
vendored
@@ -3,7 +3,7 @@ updates:
|
||||
- package-ecosystem: npm
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
interval: weekly
|
||||
time: '00:00'
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
|
||||
33
.github/workflows/codeql-analysis.yml
vendored
@@ -1,19 +1,33 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, ]
|
||||
branches: [main]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
branches: [main]
|
||||
schedule:
|
||||
- cron: '0 13 * * 0'
|
||||
- cron: '0 0 * * 6'
|
||||
|
||||
jobs:
|
||||
analyse:
|
||||
name: Analyse
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Override automatic language detection by changing the below list
|
||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||
language: ['javascript']
|
||||
# Learn more...
|
||||
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
@@ -30,9 +44,12 @@ jobs:
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
# with:
|
||||
# languages: go, javascript, csharp, python, cpp, java
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
|
||||
6
.gitignore
vendored
@@ -26,7 +26,7 @@ coverage
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
@@ -93,8 +93,8 @@ sw.*
|
||||
# Vim swap files
|
||||
*.swp
|
||||
|
||||
# Postwoman build data
|
||||
.postwoman
|
||||
# Build data
|
||||
.hoppscotch
|
||||
|
||||
# File explorer
|
||||
.directory
|
||||
|
||||
1
.husky/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
_
|
||||
4
.husky/pre-commit
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npm run pre-commit
|
||||
@@ -1,7 +1,8 @@
|
||||
.dependabot
|
||||
.github
|
||||
.nuxt
|
||||
.postwoman
|
||||
.hoppscotch
|
||||
.vscode
|
||||
package-lock.json
|
||||
node_modules
|
||||
node_modules
|
||||
dist
|
||||
3
.prettierrc.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
semi: false
|
||||
}
|
||||
24
.stylelintrc.js
Normal file
@@ -0,0 +1,24 @@
|
||||
module.exports = {
|
||||
extends: ["stylelint-config-standard", "stylelint-config-prettier"],
|
||||
// add your custom config here
|
||||
// https://stylelint.io/user-guide/configuration
|
||||
rules: {
|
||||
"at-rule-no-unknown": [
|
||||
true,
|
||||
{
|
||||
ignoreAtRules: [
|
||||
"extends",
|
||||
"tailwind",
|
||||
"apply",
|
||||
"variants",
|
||||
"responsive",
|
||||
"screen",
|
||||
"mixin",
|
||||
"include",
|
||||
],
|
||||
},
|
||||
],
|
||||
"declaration-block-trailing-semicolon": null,
|
||||
"no-descending-specificity": null,
|
||||
},
|
||||
}
|
||||
@@ -15,16 +15,11 @@ node_js:
|
||||
|
||||
os: linux
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libgconf-2-4 # cypress binary dependency
|
||||
|
||||
cache: npm
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- main
|
||||
|
||||
install:
|
||||
- npm ci
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# Changelog
|
||||
|
||||
## [v1.12.0](https://github.com/hoppscotch/hoppscotch/tree/v1.12.0) (2020-05-27)
|
||||
|
||||
[Full Changelog](https://github.com/hoppscotch/hoppscotch/compare/v1.10.0...v1.12.0)
|
||||
|
||||
## [v1.10.0](https://github.com/hoppscotch/hoppscotch/tree/v1.10.0) (2020-04-10)
|
||||
|
||||
[Full Changelog](https://github.com/hoppscotch/hoppscotch/compare/v1.9.9...v1.10.0)
|
||||
|
||||
## [v1.9.9](https://github.com/liyasthomas/postwoman/tree/v1.9.9) (2020-07-30)
|
||||
|
||||
[Full Changelog](https://github.com/liyasthomas/postwoman/compare/v1.9.7...v1.9.9)
|
||||
|
||||
@@ -2,75 +2,131 @@
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
- The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior. Maintainers are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned with our Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at hello@postwoman.io. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
reported to the community leaders responsible for enforcement at
|
||||
[INSERT CONTACT METHOD].
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][mozilla coc].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][faq]. Translations are available
|
||||
at [https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
|
||||
[mozilla coc]: https://github.com/mozilla/diversity
|
||||
[faq]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
|
||||
@@ -12,81 +12,6 @@ Please note we have a code of conduct, please follow it in all your interactions
|
||||
2. Update the README.md with details of changes to the interface, this includes new environment
|
||||
variables, exposed ports, useful file locations and container parameters.
|
||||
3. Increase the version numbers in any examples files and the README.md to the new version that this
|
||||
Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
|
||||
Pull Request would represent. The versioning scheme we use is [SemVer](https://semver.org).
|
||||
4. You may merge the Pull Request once you have the sign-off of two other developers, or if you
|
||||
do not have permission to do that, you may request the second reviewer merge it for you.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
### Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
### Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
### Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior. Maintainers are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned with our Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
### Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
### Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
### Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
|
||||
12
Dockerfile
@@ -1,21 +1,25 @@
|
||||
FROM node:12.10.0-alpine
|
||||
|
||||
LABEL maintainer="Liyas Thomas (liyascthomas@gmail.com)"
|
||||
LABEL maintainer="Hoppscotch (support@hoppscotch.io)"
|
||||
|
||||
# Add git as the prebuild target requires it to parse version information
|
||||
RUN apk add --update --no-cache \
|
||||
git
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN npm install
|
||||
|
||||
ADD . /app/
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm run build
|
||||
|
||||
ENV HOST 0.0.0.0
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["npm", "run", "start"]
|
||||
RUN mv .env.example .env
|
||||
|
||||
CMD ["npm", "run", "dev"]
|
||||
|
||||
109
GITHUB_EXTERNSHIP.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# **GitHub Externship @ Hoppscotch**
|
||||
|
||||
**We ❤️ open source**
|
||||
|
||||
We are super excited to be a ‘Partner Organization’ of GitHub Externship 2021 and look forward to supporting all interested students to participate and contribute to our [open source projects](https://github.com/hoppscotch).
|
||||
|
||||
This document covers the process, expectations and guidelines for any interested student so that we can guide, mentor in the best possible manner and most importantly review your community engagement which is a critical factor along with your project idea to be selected from our organization.
|
||||
|
||||
**This post will be updated from time to time. So please keep an eye on it.**
|
||||
|
||||
Before, any of you jump in and start contributing, here are a few documents from the GitHub Externship Team which we advise every student to read through carefully and thoroughly:
|
||||
|
||||
- [GitHub Externship: Website](https://github-externships.github.io/externship/index.html)
|
||||
- [GitHub Externship: Program Structure](https://github-externships.github.io/externship/structure.html)
|
||||
|
||||
Our awesome community members frequently request for features on our [Discord server](https://hoppscotch.io/discord), [Telegram group](https://hoppscotch.io/externship_telegram), [GitHub issues tab](https://github.com/hoppscotch/hoppscotch/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) and we have a never ending list of awesome ideas. However, keeping in mind the 3 months time span, we have filtered through our stockpile and come up with the following ideas for [GitHub Externship](https://github-externships.github.io/externship/index.html) program.
|
||||
|
||||
## **Ideas**
|
||||
|
||||
If you’re a student interested in working with Hoppscotch during GitHub Externship, we’ve assembled for you a list of 20 ideas under the following three categories:
|
||||
|
||||
### **1. Implement existing feature requests:**
|
||||
|
||||
- [gRPC-Web support](https://github.com/hoppscotch/hoppscotch/issues/402)
|
||||
|
||||
Like swagger, let users view message formats from `.proto` / `URL` and test the server methods by sending any messages from the Hoppscotch.
|
||||
|
||||
[**`Learn more →`**](https://github.com/hoppscotch/hoppscotch/issues/402)
|
||||
|
||||
- [Swagger / OpenAPI support](https://github.com/hoppscotch/hoppscotch/issues/470)
|
||||
|
||||
Like [Swagger Inspector](https://inspector.swagger.io/builder) / [Swagger Editor](https://editor.swagger.io). Let users import `swagger.json` and test the server methods by sending any messages from the Hoppscotch.
|
||||
|
||||
[**`Learn more →`**](https://github.com/hoppscotch/hoppscotch/issues/470)
|
||||
|
||||
- [Mock Server](https://github.com/hoppscotch/hoppscotch/issues/1598)
|
||||
|
||||
Mock server allows users to create mock endpoints that accepts request from the system-under-test or from a `json` file.
|
||||
|
||||
[**`Learn more →`**](https://github.com/hoppscotch/hoppscotch/issues/1598)
|
||||
|
||||
### **2. Implement new features:**
|
||||
|
||||
If you'd like to implement a totally new feature to help developers make API testing easy, feel free to come up with your own feature request or a port of feature from other API testing tools.
|
||||
|
||||
[**Create new feature request →**](https://github.com/hoppscotch/hoppscotch/issues/new?assignees=&labels=&template=feature_request.md&title=Feature%20[GitHub%20Externship]:)
|
||||
|
||||
### **3. Refactor existing features:**
|
||||
|
||||
If you'd like to refactor an already implemented feature / workflow - feel free to open a PR to do that. We appreciate using industry best pratices and latest technologies on all of our open source projects.
|
||||
|
||||
## **Built with**
|
||||
|
||||
- [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML)
|
||||
- [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS), [SCSS](https://sass-lang.com), [Tailwind CSS](https://tailwindcss.com)
|
||||
- [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
||||
- [TypeScript](https://www.typescriptlang.org)
|
||||
- [Vue](https://vuejs.org)
|
||||
- [Nuxt](https://nuxtjs.org)
|
||||
|
||||
## **Contributing**
|
||||
|
||||
Please contribute using [GitHub Flow](https://guides.github.com/introduction/flow). Create a branch, add commits, and [open a pull request](https://github.com/hoppscotch/hoppscotch/compare).
|
||||
|
||||
Please read [`CONTRIBUTING`](CONTRIBUTING.md) for details on our [`CODE OF CONDUCT`](CODE_OF_CONDUCT.md), and the process for submitting pull requests to us.
|
||||
|
||||
## **Quick links**
|
||||
|
||||
[**`Repository →`**](https://github.com/hoppscotch/hoppscotch)
|
||||
|
||||
[**`Web app →`**](https://hoppscotch.io)
|
||||
|
||||
[**`Discord server →`**](https://hoppscotch.io/discord)
|
||||
|
||||
[**`Telegram group →`**](https://hoppscotch.io/externship_telegram)
|
||||
|
||||
## **Discussions channel**
|
||||
|
||||
We use [GitHub Discussions](https://github.com/hoppscotch/hoppscotch/discussions) as the primary channel for anything and everything related to GitHub Externship, ranging from
|
||||
|
||||
- Queries on issues you’re working or thinking about to take up.
|
||||
- Mentor advice on your project ideas [Google Drive document once there is enough clarity for easier collaboration and feedback – check project proposal ideas above]
|
||||
- Helping out your friends to onboard and contribute
|
||||
- Finally even selection updates etc.
|
||||
|
||||
Before asking a question please check this [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask)
|
||||
|
||||
## **Need help?**
|
||||
|
||||
Start a discussion [here](https://github.com/hoppscotch/hoppscotch/discussions) if you’re unable to get a response from the [Telegram](https://hoppscotch.io/externship_telegram), [Discord](https://hoppscotch.io/discord) communities.
|
||||
|
||||
Start a new idea under [discussions](https://github.com/hoppscotch/hoppscotch/discussions) only once you’ve finalized your project proposal.
|
||||
|
||||
Send us an email at support@hoppscotch.io for any administrative or operational concerns regarding the program.
|
||||
|
||||
## **Submit your proposal on time**
|
||||
|
||||
You can find the complete GitHub Externship program timeline [here](https://github-externships.github.io/externship/structure.html). Students can begin registering and submitting project proposals to mentor organizations—including Hoppscotch—on April 22, 2021.
|
||||
|
||||
All proposals must be submitted by May 21, 2021.
|
||||
|
||||
We look forward to seeing your proposals for a happy summer of coding.
|
||||
|
||||
## **Mentors**
|
||||
|
||||
- [Liyas Thomas](https://github.com/liyasthomas)
|
||||
- [Andrew Bastin](https://github.com/andrewbastin)
|
||||
|
||||
If you have any questions or queries please contact us via [Telegram](https://hoppscotch.io/externship_telegram), [Discord](https://hoppscotch.io/discord) or send an email to us at support@hoppscotch.io.
|
||||
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Liyas Thomas
|
||||
Copyright (c) 2020
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
705
README.md
@@ -1,107 +1,140 @@
|
||||
<div align="center">
|
||||
<a href="https://postwoman.io"><img src="https://raw.githubusercontent.com/liyasthomas/postwoman/master/static/logo.png" alt="Postwoman.io logo" height="160"></a>
|
||||
<a href="https://hoppscotch.io"><img src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/static/logo.png" alt="hoppscotch.io logo" height="128"></a>
|
||||
<br>
|
||||
<br>
|
||||
<p>
|
||||
<b>A free, fast and beautiful API request builder</b>
|
||||
<b>Hoppscotch - Open source API development ecosystem</b>
|
||||
</p>
|
||||
<p>
|
||||
<i>Web alternative to Postman - Helps you create requests faster, saving precious time on development - <a href="https://postwoman.launchaco.com">Subscribe</a></i>
|
||||
<i>Helps you create requests faster, saving precious time on development - <a href="https://eepurl.com/g6n_P5">Subscribe</a></i>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
[](https://travis-ci.com/liyasthomas/postwoman) [](https://github.com/liyasthomas/postwoman/releases/latest) [](https://postwoman.io) [](CONTRIBUTING.md) [](https://opencollective.com/postwoman) [](https://www.paypal.me/liyascthomas) [](https://t.me/postwoman_app) [](https://discord.gg/GAMWxmR) [](https://twitter.com/intent/tweet?url=https%3A%2F%2Fpostwoman.io&text=%F0%9F%91%BD%20Postwoman%20%E2%80%A2%20API%20request%20builder%20-%20Helps%20you%20create%20your%20requests%20faster%2C%20saving%20you%20precious%20time%20on%20your%20development&original_referer=https%3A%2F%2Ftwitter.com%2Fshare%3Ftext%3D%25F0%259F%2591%25BD%2520Postwoman%2520%25E2%2580%25A2%2520API%2520request%2520builder%2520-%2520Helps%2520you%2520create%2520your%2520requests%2520faster%2C%2520saving%2520you%2520precious%2520time%2520on%2520your%2520development%26url%3Dhttps%3A%2F%2Fpostwoman.io%26hashtags%3Dpostwoman%26via%3Dliyasthomas&via=liyasthomas&hashtags=postwoman)
|
||||
[](CODE_OF_CONDUCT.md) [](https://hoppscotch.io) [](https://travis-ci.com/hoppscotch/hoppscotch) [](https://twitter.com/share?text=%F0%9F%91%BD%20Hoppscotch%20%E2%80%A2%20Open%20source%20API%20development%20ecosystem%20-%20Helps%20you%20create%20requests%20faster,%20saving%20precious%20time%20on%20development.&url=https://hoppscotch.io&hashtags=hoppscotch&via=hoppscotch_io)
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<sub>Built with ❤︎ by
|
||||
<a href="https://github.com/liyasthomas">liyasthomas</a> and
|
||||
<a href="https://github.com/liyasthomas/postwoman/graphs/contributors">contributors</a>
|
||||
<a href="https://github.com/hoppscotch/hoppscotch/graphs/contributors">contributors</a>
|
||||
</sub>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
**Read: [Story behind Postwoman](https://dev.to/liyasthomas/i-created-postwoman-an-online-open-source-api-request-builder-41md)**
|
||||
|
||||
**Chat: [Telegram](https://t.me/postwoman_app), [Discord](https://discord.gg/GAMWxmR)**
|
||||
|
||||
**Donate: [GitHub Sponsors](https://github.com/sponsors/postwoman-io), [Open Collective](https://opencollective.com/postwoman), [Patreon](https://www.patreon.com/liyasthomas), [PayPal](https://www.paypal.me/liyascthomas)**
|
||||
<p align="center">
|
||||
<b>Sponsored by</b>
|
||||
<br>
|
||||
<br>
|
||||
<a href="https://appwrite.io/?utm_source=hoppscotch&utm_medium=banner&utm_campaign=hello" title="Appwrite" target="_blank">
|
||||
<img height="60px" src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/assets/images/appwrite-banner.svg" title="Appwrite">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
<a href="https://postwoman.io"><img src="https://raw.githubusercontent.com/liyasthomas/postwoman/master/static/images/screenshot1.png" alt="Screenshot1" width="100%"></a>
|
||||
<a href="https://hoppscotch.io"><img src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/static/images/screenshots/banner_dark.png" alt="Screenshot" width="100%"></a>
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<b>Powered by</b>
|
||||
<br>
|
||||
<br>
|
||||
<a href="https://oss.capital/?ref=hoppscotch" title="OSS Capital" target="_blank">
|
||||
<img height="100px" src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/assets/images/ossc-banner.svg" title="OSS Capital">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
#### **Contact**
|
||||
|
||||
[](https://hoppscotch.io/telegram) [](https://hoppscotch.io/discord)
|
||||
|
||||
#### **Support**
|
||||
|
||||
[](https://github.com/sponsors/hoppscotch) [](https://opencollective.com/hoppscotch) [](https://www.patreon.com/liyasthomas) [](https://www.paypal.me/liyascthomas)
|
||||
|
||||
<details>
|
||||
<summary>Table of contents</summary>
|
||||
<summary><i>Table of contents</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- [Features](#features-)
|
||||
- [Demo](#demo--)
|
||||
- [Usage](#usage-)
|
||||
- [Built with](#built-with-)
|
||||
- [Developing](#developing-)
|
||||
- [Features](#features)
|
||||
- [Demo](#demo)
|
||||
- [Usage](#usage)
|
||||
- [Built with](#built-with)
|
||||
- [Developing](#developing)
|
||||
- [Browser based development environment](#browser-based-development-environment)
|
||||
- [Local development environment](#local-development-environment)
|
||||
- [Docker compose](#docker-compose)
|
||||
- [Docker](#docker--)
|
||||
- [Releasing](#releasing-)
|
||||
- [Contributing](#contributing-)
|
||||
- [Continuous Integration](#continuous-integration--)
|
||||
- [Versioning](#versioning--)
|
||||
- [Change log](#change-log-)
|
||||
- [Authors](#authors-)
|
||||
- [Docker](#docker)
|
||||
- [Releasing](#releasing)
|
||||
- [Contributing](#contributing)
|
||||
- [Continuous Integration](#continuous-integration)
|
||||
- [Changelog](#changelog)
|
||||
- [Authors](#authors)
|
||||
- [Lead Developers](#lead-developers)
|
||||
- [Testing and Debugging](#testing-and-debugging)
|
||||
- [Collaborators](#collaborators-)
|
||||
- [Thanks](#thanks)
|
||||
- [Financial Contributors](#financial-contributors)
|
||||
- [Organizations](#organizations)
|
||||
- [Individuals](#individuals)
|
||||
- [GitHub Sponsors](#github-sponsors)
|
||||
- [Open Collective](#open-collective)
|
||||
- [Code Contributors](#code-contributors)
|
||||
- [License](#license-)
|
||||
- [Acknowledgements](#acknowledgements-)
|
||||
- [Badges](#badges-)
|
||||
- [License](#license)
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
### Features ✨
|
||||
### **Features**
|
||||
|
||||
❤️ **Lightweight**: Crafted with minimalistic UI design.
|
||||
❤️ **Lightweight:** Crafted with minimalistic UI design.
|
||||
|
||||
⚡️ **Fast**: Send requests and get/copy responses in real-time.
|
||||
⚡️ **Fast:** Send requests and get/copy responses in real-time.
|
||||
|
||||
**Methods:**
|
||||
<details>
|
||||
<summary><i>HTTP Methods</i></summary>
|
||||
|
||||
- `GET` - Retrieve information about the REST API resource
|
||||
---
|
||||
|
||||
- `GET` - Requests retrieve resource information
|
||||
- `HEAD` - Retrieve response headers identical to those of a GET request, but without the response body.
|
||||
- `POST` - Create a REST API resource
|
||||
- `PUT` - Update a REST API resource
|
||||
- `DELETE` - Delete a REST API resource or related component
|
||||
- `POST` - The server creates a new entry in a database
|
||||
- `PUT` - Updates an existing resource
|
||||
- `DELETE` - Deletes resource or related component
|
||||
- `CONNECT` - Establishes a tunnel to the server identified by the target resource
|
||||
- `OPTIONS` - Describe the communication options for the target resource
|
||||
- `TRACE` - Performs a message loop-back test along the path to the target resource
|
||||
- `PATCH` - Apply partial modifications to a REST API resource
|
||||
- `PATCH` - Very similar to `PUT` but makes a partial update on a resource
|
||||
- `<custom>` - Some APIs use custom request methods such as `LIST`. Type in your custom methods.
|
||||
|
||||
🌈 **Make it yours**: Customizable combinations for background, foreground and accent colors.
|
||||
---
|
||||
|
||||
**Theming:** [Customize now ✨](https://postwoman.io/settings)
|
||||
</details>
|
||||
|
||||
- Choose theme: Kinda Dark (default), Clearly White, Just Black and System theme
|
||||
- Choose accent color: Green (default), Yellow, Pink, Red, Purple, Orange, Cyan and Blue
|
||||
- Toggle multi-colored headings
|
||||
🌈 **Make it yours:** Customizable combinations for background, foreground and accent colors. [Customize now ✨](https://hoppscotch.io/settings)
|
||||
|
||||
<details>
|
||||
<summary><i>Theming</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Choose theme: System, Light, Dark (default) and Black
|
||||
- Choose accent color: Blue, Green (default), Teal, Indigo, Purple, Orange, Pink, Red, and Yellow
|
||||
- Toggle auto-scroll to response
|
||||
|
||||
<p>
|
||||
<a href="https://hoppscotch.io"><img src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/static/images/screenshots/banner_light.png" alt="Screenshot" width="100%"></a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
_Customized themes are synced with local session storage_
|
||||
|
||||
🔥 **PWA**: Install as a [PWA](https://developers.google.com/web/progressive-web-apps) on your device.
|
||||
🔥 **PWA:** Install as a [PWA](https://developers.google.com/web/progressive-web-apps) on your device.
|
||||
|
||||
**Features:**
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Instant loading with Service Workers
|
||||
- Offline support
|
||||
@@ -109,31 +142,44 @@ _Customized themes are synced with local session storage_
|
||||
- Add to Home Screen
|
||||
- Desktop PWA
|
||||
|
||||
🚀 **Request**: Retrieve response from endpoint instantly.
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
🚀 **Request:** Retrieve response from endpoint instantly.
|
||||
|
||||
- Choose `method`
|
||||
- Enter `URL`
|
||||
- Send
|
||||
|
||||
**Features:**
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Copy/share public "Share URL"
|
||||
- Generate/copy request code for `JavaScript XHR`, `Fetch` and `cURL`
|
||||
- Generate/copy request code snippets for 10+ languages and frameworks
|
||||
- Import `cURL`
|
||||
- Label requests
|
||||
|
||||
🔌 **WebSocket**: Establish full-duplex communication channels over a single TCP connection.
|
||||
---
|
||||
|
||||
- Send and receive data
|
||||
- Basic and Bearer Token authentication
|
||||
</details>
|
||||
|
||||
📡 **Server Sent Events**: Receive a stream of updates from a server over a HTTP connection without resorting to polling.
|
||||
🔌 **WebSocket:** Establish full-duplex communication channels over a single TCP connection.
|
||||
|
||||
🌩 **Socket.IO**: Send and Receive data with SocketIO server.
|
||||
📡 **Server Sent Events:** Receive a stream of updates from a server over a HTTP connection without resorting to polling.
|
||||
|
||||
🦟 **MQTT**: Subscribe and Publish to topics of a MQTT Broker.
|
||||
🌩 **Socket.IO:** Send and Receive data with SocketIO server.
|
||||
|
||||
🔮 **GraphQL**: GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data.
|
||||
🦟 **MQTT:** Subscribe and Publish to topics of a MQTT Broker.
|
||||
|
||||
🔮 **GraphQL:** GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data.
|
||||
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Set endpoint and get schemas
|
||||
- Multi-column docs
|
||||
@@ -141,9 +187,16 @@ _Customized themes are synced with local session storage_
|
||||
- Query schema
|
||||
- Get query response
|
||||
|
||||
🔐 **Authentication**: Allows to identify the end user.
|
||||
---
|
||||
|
||||
**Types:**
|
||||
</details>
|
||||
|
||||
🔐 **Authentication:** Allows to identify the end user.
|
||||
|
||||
<details>
|
||||
<summary><i>Types</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- None
|
||||
- Basic
|
||||
@@ -151,158 +204,263 @@ _Customized themes are synced with local session storage_
|
||||
- OAuth 2.0
|
||||
- OIDC Access Token/PKCE
|
||||
|
||||
📢 **Headers**: Describes the format the body of your request is being sent as.
|
||||
---
|
||||
|
||||
📫 **Parameters**: Use request parameters to set varying parts in simulated requests.
|
||||
</details>
|
||||
|
||||
📃 **Request Body**: Used to send and receive data via the REST API.
|
||||
📢 **Headers:** Describes the format the body of your request is being sent as.
|
||||
|
||||
**Options:**
|
||||
📫 **Parameters:** Use request parameters to set varying parts in simulated requests.
|
||||
|
||||
📃 **Request Body:** Used to send and receive data via the REST API.
|
||||
|
||||
<details>
|
||||
<summary><i>Options</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Set `Content Type`
|
||||
- Add or remove Parameter list
|
||||
- Toggle between key-value and RAW input parameter list
|
||||
|
||||
👋 **Responses**: Contains the status line, headers and the message/response body.
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
👋 **Response:** Contains the status line, headers and the message/response body.
|
||||
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Copy response to clipboard
|
||||
- Download response as a file
|
||||
- View preview of HTML responses
|
||||
- View response headers
|
||||
- View raw and preview of HTML, image, JSON, XML responses
|
||||
|
||||
⏰ **History**: Request entries are synced with cloud / local session storage to restore with a single click.
|
||||
---
|
||||
|
||||
📁 **Collections**: Keep your API requests organized with collections and folders. Reuse them with a single click.
|
||||
</details>
|
||||
|
||||
⏰ **History:** Request entries are synced with cloud / local session storage to restore with a single click.
|
||||
|
||||
📁 **Collections:** Keep your API requests organized with collections and folders. Reuse them with a single click.
|
||||
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Unlimited collections, folders and requests
|
||||
- Nested folders
|
||||
- Export as / import from GitHub gist
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
_Collections are synced with cloud / local session storage_
|
||||
|
||||
🌐 **Proxy**: Enable Proxy Mode from Settings to access blocked APIs.
|
||||
🌐 **Proxy:** Enable Proxy Mode from Settings to access blocked APIs.
|
||||
|
||||
**Features:**
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Hide your IP address
|
||||
- Fixes [`CORS`](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) (Cross Origin Resource Sharing) issues
|
||||
- Access APIs served in non-HTTPS (`http://`)
|
||||
- Use custom Proxy URL
|
||||
|
||||
_Official Postwoman Proxy is hosted by Apollo Software - **[Privacy Policy](https://apollosoftware.xyz/legal/postwoman)**_
|
||||
---
|
||||
|
||||
📜 **Pre-Request Scripts β**: Snippets of code associated with a request that are executed before the request is sent.
|
||||
</details>
|
||||
|
||||
**Use-cases:**
|
||||
_Official proxy server is hosted by Hoppscotch - **[GitHub](https://github.com/hoppscotch/proxyscotch)** - **[Privacy Policy](https://github.com/hoppscotch/proxyscotch/wiki/Privacy-policy)**_
|
||||
|
||||
📜 **Pre-Request Scripts β:** Snippets of code associated with a request that are executed before the request is sent.
|
||||
|
||||
<details>
|
||||
<summary><i>Use-cases</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Initialize environment variables
|
||||
- Include timestamp in the request headers
|
||||
- Send a random alphanumeric string in the URL parameters
|
||||
|
||||
📄 **API Documentation**: Create and share dynamic API documentation easily, quickly.
|
||||
---
|
||||
|
||||
**Usage:**
|
||||
</details>
|
||||
|
||||
📄 **API Documentation:** Create and share dynamic API documentation easily, quickly.
|
||||
|
||||
<details>
|
||||
<summary><i>Usage</i></summary>
|
||||
|
||||
---
|
||||
|
||||
1. Add your requests to Collections and Folders
|
||||
2. Export Collections and easily share your APIs with the rest of your team
|
||||
3. Import Collections and Generate Documentation on-the-go
|
||||
|
||||
⌨️ **Keyboard Shortcuts**: Optimized for efficiency.
|
||||
---
|
||||
|
||||
**Shortcuts:**
|
||||
</details>
|
||||
|
||||
- Send/Cancel Request <kbd>Ctrl</kbd> + <kbd>G</kbd>
|
||||
- Save to Collections <kbd>Ctrl</kbd> + <kbd>S</kbd>
|
||||
- Copy Request Link <kbd>Ctrl</kbd> + <kbd>K</kbd>
|
||||
- Reset Request <kbd>Ctrl</kbd> + <kbd>L</kbd>
|
||||
⌨️ **Keyboard Shortcuts:** Optimized for efficiency.
|
||||
|
||||
🌎 **i18n β**: Experience the app in your own language.
|
||||
> **[Shortcuts WIki](https://github.com/hoppscotch/hoppscotch/wiki/Shortcuts)**
|
||||
|
||||
🌎 **i18n:** Experience the app in your own language.
|
||||
|
||||
<details>
|
||||
<summary><i>Usage</i></summary>
|
||||
|
||||
---
|
||||
|
||||
1. Scroll down to the footer
|
||||
2. Click "Choose Language" icon button
|
||||
3. Select your language from the menu
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
_Keep in mind: Translations aren't available for all source and target language combinations_
|
||||
|
||||
**To provide a localized experience for users around the world, you can add you own translations.**
|
||||
|
||||
_**All `i18n` contributions are welcome to `i18n` [branch](https://github.com/liyasthomas/postwoman/tree/i18n) only!**_
|
||||
_**All `i18n` contributions are welcome to `i18n` [branch](https://github.com/hoppscotch/hoppscotch/tree/i18n) only!**_
|
||||
|
||||
📦 **Add-ons**: Official add-ons for Postwoman.
|
||||
📦 **Add-ons:** Official add-ons for hoppscotch.
|
||||
|
||||
- **[Proxy](https://github.com/postwoman-io/proxywoman)** - A simple proxy server created for Postwoman
|
||||
- **[CLI β](https://github.com/postwoman-io/postwoman-cli)** - A CLI solution for Postwoman
|
||||
- **[Browser Extensions](https://github.com/AndrewBastin/postwoman-extension)** - Browser extensions that simplifies access to Postwoman
|
||||
- **[Proxy](https://github.com/hoppscotch/proxyscotch)** - A simple proxy server created for Hoppscotch
|
||||
- **[CLI β](https://github.com/hoppscotch/hopp-cli)** - A CLI solution for Hoppscotch
|
||||
- **[Browser Extensions](https://github.com/hoppscotch/hoppscotch-extension)** - Browser extensions that simplifies access to Hoppscotch
|
||||
|
||||
[ **Firefox**](https://addons.mozilla.org/en-US/firefox/addon/postwoman) | [ **Chrome**](https://chrome.google.com/webstore/detail/postwoman-extension-for-c/amknoiejhlmhancpahfcfcfhllgkpbld)
|
||||
[ **Firefox**](https://addons.mozilla.org/en-US/firefox/addon/hoppscotch) | [ **Chrome**](https://chrome.google.com/webstore/detail/hoppscotch-extension-for-c/amknoiejhlmhancpahfcfcfhllgkpbld)
|
||||
|
||||
> **Extensions fixes `CORS` issues.**
|
||||
|
||||
_Add-ons are developed and maintained under **[Official Postwoman Organization](https://github.com/postwoman-io)**._
|
||||
- **[Hopp-Doc-Gen](https://github.com/hoppscotch/hopp-doc-gen)** - An API doc generator CLI for Hoppscotch
|
||||
|
||||
☁️ **Auth + Sync**: Sign in and sync in real-time.
|
||||
_Add-ons are developed and maintained under **[Official Hoppscotch Organization](https://github.com/hoppscotch)**._
|
||||
|
||||
**Sign in with:**
|
||||
☁️ **Auth + Sync:** Sign in and sync in real-time.
|
||||
|
||||
**Sign in with**
|
||||
|
||||
- Google
|
||||
- GitHub
|
||||
|
||||
**Sync:**
|
||||
**Sync**
|
||||
|
||||
- History
|
||||
- Collections
|
||||
- Environments
|
||||
- Notes
|
||||
|
||||
✅ **Post-Request Tests β**: Write tests associated with a request that are executed after the request response.
|
||||
✅ **Post-Request Tests β:** Write tests associated with a request that are executed after the request response.
|
||||
|
||||
**Use-cases:**
|
||||
<details>
|
||||
<summary><i>Use-cases</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Check the status code as an integer
|
||||
- Filter response headers
|
||||
- Parse the response data
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
📝 **Notes** : Instantly jot down notes, tasks or whatever you feel like as they come to your mind.
|
||||
|
||||
_Notes are only available for signed-in users_
|
||||
|
||||
🌱 **Environments** : Environment variables allow you to store and reuse values in your requests and scripts.
|
||||
|
||||
**Use-cases:**
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Unlimited environments and variables
|
||||
- Initialize through pre-request script
|
||||
- Export as / import from GitHub gist
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><i>Use-cases</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- By storing a value in a variable, you can reference it throughout your request section
|
||||
- If you need to update the value, you only have to change it in one place
|
||||
- Using variables increases your ability to work efficiently and minimizes the likelihood of error
|
||||
|
||||
**To find out more, please check out [Postwoman Wiki](https://github.com/liyasthomas/postwoman/wiki).**
|
||||
---
|
||||
|
||||
## Demo 🚀 [](https://postwoman.io)
|
||||
</details>
|
||||
|
||||
[postwoman.io](https://postwoman.io)
|
||||
👨👩👧👦 **Teams β:** Helps you collaborate across your team to design, develop, and test APIs faster.
|
||||
|
||||
## Usage 💡
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Unlimited team collections and shared requests
|
||||
- Unlimited team members
|
||||
- User roles
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
**To find out more, please check out [Hoppscotch Wiki](https://github.com/hoppscotch/hoppscotch/wiki).**
|
||||
|
||||
## **Demo**
|
||||
|
||||
[hoppscotch.io](https://hoppscotch.io)
|
||||
|
||||
## **Usage**
|
||||
|
||||
1. Choose `method`
|
||||
2. Enter `URL`
|
||||
3. Send request
|
||||
4. Get response
|
||||
|
||||
## Built with 🔧
|
||||
## **Built with**
|
||||
|
||||
- HTML - For the web framework
|
||||
- CSS - For styling components
|
||||
- JavaScript - For magic!
|
||||
- [Vue](https://vuejs.org/)
|
||||
- [Nuxt](https://nuxtjs.org/)
|
||||
- [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML)
|
||||
- [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS), [SCSS](https://sass-lang.com), [Tailwind CSS](https://tailwindcss.com)
|
||||
- [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
||||
- [TypeScript](https://www.typescriptlang.org)
|
||||
- [Vue](https://vuejs.org)
|
||||
- [Nuxt](https://nuxtjs.org)
|
||||
|
||||
## Developing 👷
|
||||
## **Developing**
|
||||
|
||||
0. Update [`.env.example`](https://github.com/liyasthomas/postwoman/blob/master/.env.example) file found in repository's root directory with your own keys and rename it to `.env`.
|
||||
0. Update [`.env.example`](https://github.com/hoppscotch/hoppscotch/blob/main/.env.example) file found in repository's root directory with your own keys and rename it to `.env`.
|
||||
|
||||
_Sample keys only works with the [production build](https://postwoman.io)._
|
||||
_Sample keys only works with the [production build](https://hoppscotch.io)._
|
||||
|
||||
#### Browser based development environment
|
||||
|
||||
[](https://gitpod.io/#https://github.com/liyasthomas/postwoman)
|
||||
[](https://gitpod.io/#https://github.com/hoppscotch/hoppscotch)
|
||||
|
||||
#### Local development environment
|
||||
|
||||
1. [Clone this repo](https://help.github.com/en/articles/cloning-a-repository) with git.
|
||||
2. Install dependencies by running `npm install` within the directory that you cloned (probably `postwoman`).
|
||||
2. Install dependencies by running `npm install` within the directory that you cloned (probably `hoppscotch`).
|
||||
3. Start the development server with `npm run dev`.
|
||||
4. Open development site by going to [`http://localhost:3000`](http://localhost:3000) in your browser.
|
||||
|
||||
@@ -312,60 +470,74 @@ _Sample keys only works with the [production build](https://postwoman.io)._
|
||||
2. Run `docker-compose up`
|
||||
3. Open development site by going to [`http://localhost:3000`](http://localhost:3000) in your browser.
|
||||
|
||||
## Docker 🐳 [](https://hub.docker.com/r/liyasthomas/postwoman)
|
||||
## **Docker**
|
||||
|
||||
**Official container** [](https://hub.docker.com/r/hoppscotch/hoppscotch)
|
||||
|
||||
```bash
|
||||
#pull
|
||||
docker pull hoppscotch/hoppscotch
|
||||
|
||||
#build
|
||||
docker build -t hoppscotch/hoppscotch:latest .
|
||||
|
||||
#run
|
||||
docker run -p 3000:3000 hoppscotch/hoppscotch:latest
|
||||
```
|
||||
|
||||
**Legacy container** [](https://hub.docker.com/r/liyasthomas/postwoman)
|
||||
|
||||
<details>
|
||||
<summary><i>Legacy container</i></summary>
|
||||
|
||||
---
|
||||
|
||||
```bash
|
||||
#pull
|
||||
docker pull liyasthomas/postwoman
|
||||
|
||||
#build
|
||||
docker build -t liyasthomas/postwoman:latest .
|
||||
|
||||
#run
|
||||
docker run -p 3000:3000 liyasthomas/postwoman:latest
|
||||
|
||||
#build
|
||||
docker build -t postwoman:latest .
|
||||
```
|
||||
|
||||
## Releasing 🧞
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
## **Releasing**
|
||||
|
||||
1. [Clone this repo](https://help.github.com/en/articles/cloning-a-repository) with git.
|
||||
2. Install dependencies by running `npm install` within the directory that you cloned (probably `postwoman`).
|
||||
3. Build the release files with `npm run build`.
|
||||
2. Install dependencies by running `npm install` within the directory that you cloned (probably `hoppscotch`).
|
||||
3. Build the release files with `npm run generate`.
|
||||
4. Find the built project in `./dist`.
|
||||
|
||||
## Contributing 🍰
|
||||
## **Contributing**
|
||||
|
||||
Please contribute using [GitHub Flow](https://guides.github.com/introduction/flow). Create a branch, add commits, and [open a pull request](https://github.com/hoppscotch/hoppscotch/compare).
|
||||
|
||||
Please read [`CONTRIBUTING`](CONTRIBUTING.md) for details on our [`CODE OF CONDUCT`](CODE_OF_CONDUCT.md), and the process for submitting pull requests to us.
|
||||
|
||||
## Continuous Integration 💚 [](https://travis-ci.com/liyasthomas/postwoman)
|
||||
## **Continuous Integration**
|
||||
|
||||
We use [Travis CI](https://travis-ci.com) for continuous integration. Check out our [Travis CI Status](https://travis-ci.com/liyasthomas/postwoman).
|
||||
We use [Travis CI](https://travis-ci.com) for continuous integration. Check out our [Travis CI Status](https://travis-ci.com/hoppscotch/hoppscotch).
|
||||
|
||||
## Versioning 🔖 [](https://github.com/liyasthomas/postwoman/releases/latest)
|
||||
|
||||
This project is developed by [Liyas Thomas](https://github.com/liyasthomas) using the [Semantic Versioning specification](https://semver.org). For the versions available, see the [releases on this repository](https://github.com/liyasthomas/postwoman/releases).
|
||||
|
||||
## Change log 📝
|
||||
## **Changelog**
|
||||
|
||||
See the [`CHANGELOG`](CHANGELOG.md) file for details.
|
||||
|
||||
## Authors 🧙
|
||||
## **Authors**
|
||||
|
||||
### Lead Developers
|
||||
|
||||
- **[Liyas Thomas](https://github.com/liyasthomas)** - _Author_
|
||||
- **[John Harker](https://github.com/NBTX)** - _Lead developer_
|
||||
- **[Andrew Bastin](https://github.com/andrewbastin)** - _Lead developer_
|
||||
- **[James George](https://github.com/jamesgeorge007)** - _Lead maintainer_
|
||||
- **[Caneco](https://twitter.com/caneco)** - _Logo and banner designer_
|
||||
|
||||
### Testing and Debugging
|
||||
|
||||
- [Contributors](https://github.com/liyasthomas/postwoman/graphs/contributors)
|
||||
|
||||
### Collaborators <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
|
||||
[](#contributors-)
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
@@ -373,22 +545,8 @@ See the [`CHANGELOG`](CHANGELOG.md) file for details.
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="https://liyasthomas.web.app"><img src="https://avatars1.githubusercontent.com/u/10395817?v=4" width="100px;" alt=""/><br /><sub><b>Liyas Thomas</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=liyasthomas" title="Code">💻</a> <a href="#design-liyasthomas" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/NBTX"><img src="https://avatars3.githubusercontent.com/u/43181178?v=4" width="100px;" alt=""/><br /><sub><b>John Harker</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=NBTX" title="Code">💻</a> <a href="#design-NBTX" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://nicholaslaroux.com"><img src="https://avatars0.githubusercontent.com/u/1557529?v=4" width="100px;" alt=""/><br /><sub><b>Nicholas La Roux</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=larouxn" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/yubathom"><img src="https://avatars3.githubusercontent.com/u/4117768?v=4" width="100px;" alt=""/><br /><sub><b>Thomas Yuba</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=yubathom" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.linkedin.com/in/nickpalenchar"><img src="https://avatars1.githubusercontent.com/u/7539781?v=4" width="100px;" alt=""/><br /><sub><b>Nick Palenchar</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=nickpalenchar" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/AndrewBastin"><img src="https://avatars2.githubusercontent.com/u/9131943?v=4" width="100px;" alt=""/><br /><sub><b>Andrew Bastin</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=AndrewBastin" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/vlad0337187"><img src="https://avatars1.githubusercontent.com/u/12682937?v=4" width="100px;" alt=""/><br /><sub><b>Vladislav</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=vlad0337187" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/izerozlu"><img src="https://avatars3.githubusercontent.com/u/17386157?v=4" width="100px;" alt=""/><br /><sub><b>izerozlu</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=izerozlu" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/JacobAnavisca"><img src="https://avatars2.githubusercontent.com/u/21232366?v=4" width="100px;" alt=""/><br /><sub><b>Jacob Anavisca</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=JacobAnavisca" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://nityanandagohain.github.io"><img src="https://avatars3.githubusercontent.com/u/26831659?v=4" width="100px;" alt=""/><br /><sub><b>Nityananda Gohain</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=nityanandagohain" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/hosseinnedaee"><img src="https://avatars2.githubusercontent.com/u/42691357?v=4" width="100px;" alt=""/><br /><sub><b>Hossein Nedaee</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=hosseinnedaee" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://ghuser.io/jamesgeorge007"><img src="https://avatars2.githubusercontent.com/u/25279263?v=4" width="100px;" alt=""/><br /><sub><b>James George</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=jamesgeorge007" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://dmitryyankowski.com"><img src="https://avatars0.githubusercontent.com/u/20114263?v=4" width="100px;" alt=""/><br /><sub><b>Dmitry Yankowski</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=dmitryyankowski" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.sboulema.nl"><img src="https://avatars2.githubusercontent.com/u/1820661?v=4" width="100px;" alt=""/><br /><sub><b>Samir Boulema</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=sboulema" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://liyasthomas.web.app"><img src="https://avatars1.githubusercontent.com/u/10395817?v=4" width="100px;" alt=""/><br /><sub><b>Liyas Thomas</b></sub></a><br /><a href="https://github.com/liyasthomas/hoppscotch/commits?author=liyasthomas" title="Code">💻</a> <a href="#design-liyasthomas" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/AndrewBastin"><img src="https://avatars2.githubusercontent.com/u/9131943?v=4" width="100px;" alt=""/><br /><sub><b>Andrew Bastin</b></sub></a><br /><a href="https://github.com/liyasthomas/hoppscotch/commits?author=AndrewBastin" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -397,140 +555,143 @@ See the [`CHANGELOG`](CHANGELOG.md) file for details.
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
See the list of [contributors](https://github.com/liyasthomas/postwoman/graphs/contributors) who participated in this project.
|
||||
|
||||
### Thanks
|
||||
|
||||
- [dev.to 👩💻👨💻](https://dev.to)
|
||||
See the list of [contributors](https://github.com/hoppscotch/hoppscotch/graphs/contributors) who participated in this project.
|
||||
|
||||
### Financial Contributors
|
||||
|
||||
Become a financial contributor and help us sustain our community [[Contribute](https://opencollective.com/postwoman/contribute)].
|
||||
Become a financial contributor and help us sustain our community [[Support](#support)].
|
||||
|
||||
#### Organizations
|
||||
#### GitHub Sponsors
|
||||
|
||||
Support this project with your organization. Your logo will show up here with a link to your website [[Contribute](https://opencollective.com/postwoman/contribute)].
|
||||
<p align="center">
|
||||
<a href="https://simplescraper.io/?utm_source=hs" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="100"
|
||||
src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/assets/images/Simplescraper.png"
|
||||
alt="Simplescraper"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<a href="https://opencollective.com/postwoman/organization/0/website"><img src="https://opencollective.com/postwoman/organization/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/postwoman/organization/1/website"><img src="https://opencollective.com/postwoman/organization/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/postwoman/organization/2/website"><img src="https://opencollective.com/postwoman/organization/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/postwoman/organization/3/website"><img src="https://opencollective.com/postwoman/organization/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/postwoman/organization/4/website"><img src="https://opencollective.com/postwoman/organization/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/postwoman/organization/5/website"><img src="https://opencollective.com/postwoman/organization/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/postwoman/organization/6/website"><img src="https://opencollective.com/postwoman/organization/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/postwoman/organization/7/website"><img src="https://opencollective.com/postwoman/organization/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/postwoman/organization/8/website"><img src="https://opencollective.com/postwoman/organization/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/postwoman/organization/9/website"><img src="https://opencollective.com/postwoman/organization/9/avatar.svg"></a>
|
||||
<p align="center">
|
||||
<a href="https://github.com/anmolm96" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/anmolm96.png?size=64"
|
||||
alt="Anmol Maini"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/juzhiyuan" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/juzhiyuan.png?size=64"
|
||||
alt="琚致远"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/eldadfux" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/eldadfux.png?size=64"
|
||||
alt="Eldad A. Fux"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/aishwarydhare" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/aishwarydhare.png?size=64"
|
||||
alt="Aishwary Dhare"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/rithish" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/rithish.png?size=64"
|
||||
alt="Rithish"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/ankumar" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/ankumar.png?size=64"
|
||||
alt="Anil Kumar"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/gpeal" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/gpeal.png?size=64"
|
||||
alt="Gabriel Peal"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/donokuda" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/donokuda.png?size=64"
|
||||
alt="Don Okuda"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/ebrescia" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/ebrescia.png?size=64"
|
||||
alt="Erica Brescia"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/mlynch" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/mlynch.png?size=64"
|
||||
alt="Max Lynch"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/brianshaler" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/brianshaler.png?size=64"
|
||||
alt="Brian Shaler"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/mxstbr" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/mxstbr.png?size=64"
|
||||
alt="Max Stoiber"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/jjcaine" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/jjcaine.png?size=64"
|
||||
alt="John Caine"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
#### Individuals
|
||||
#### Open Collective
|
||||
|
||||
<a href="https://opencollective.com/postwoman"><img src="https://opencollective.com/postwoman/individuals.svg"></a>
|
||||
<p align="center">
|
||||
<a href="https://pipedream.com/?ref=hoppscotch" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="100"
|
||||
src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/assets/images/pipedream.png"
|
||||
alt="pipedream"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://paw.cloud/?utm_source=hoppscotch&utm_medium=github&utm_campaign=hoppscotch-sponsorship" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="100"
|
||||
src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/assets/images/Paw-Logo-for-Hoppscotch.png"
|
||||
alt="Paw"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
### Code Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute [[Contribute](CONTRIBUTING.md)].
|
||||
|
||||
<a href="https://github.com/liyasthomas/postwoman/graphs/contributors"><img src="https://opencollective.com/postwoman/contributors.svg?width=890&button=false" /></a>
|
||||
<a href="https://github.com/hoppscotch/hoppscotch/graphs/contributors"><img src="https://opencollective.com/hoppscotch/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
## License 📄
|
||||
## **License**
|
||||
|
||||
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT) - see the [`LICENSE`](LICENSE) file for details.
|
||||
|
||||
## Acknowledgements 🙏
|
||||
|
||||
- Hat tip to anyone whose code was used
|
||||
- Inspirations:
|
||||
- [Dribbble](https://dribbble.com)
|
||||
|
||||
## Badges 📛
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Preview</th>
|
||||
<th>Markdown code</th>
|
||||
</tr>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" width="200px">
|
||||
<a href="https://postwoman.io">
|
||||
<br/>
|
||||
<img src="https://img.shields.io/badge/Tested_on-Postwoman-202124?logo=Postwoman"/>
|
||||
</a>
|
||||
<br/>
|
||||
<sub>
|
||||
Default
|
||||
</sub>
|
||||
</td>
|
||||
<td>
|
||||
<code>[](https://postwoman.io)</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" width="200px">
|
||||
<a href="https://postwoman.io">
|
||||
<br/>
|
||||
<img src="https://img.shields.io/badge/Tested_on-Postwoman-success?logo=Postwoman"/>
|
||||
</a>
|
||||
<br/>
|
||||
<sub>
|
||||
Success
|
||||
</sub>
|
||||
</td>
|
||||
<td>
|
||||
<code>[](https://postwoman.io)</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" width="200px">
|
||||
<a href="https://postwoman.io">
|
||||
<br/>
|
||||
<img src="https://img.shields.io/badge/Tested_on-Postwoman-critical?logo=Postwoman"/>
|
||||
</a>
|
||||
<br/>
|
||||
<sub>
|
||||
Critical
|
||||
</sub>
|
||||
</td>
|
||||
<td>
|
||||
<code>[](https://postwoman.io)</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" width="200px">
|
||||
<a href="https://postwoman.io">
|
||||
<br/>
|
||||
<img src="https://img.shields.io/badge/Tested_on-Postwoman-blueviolet?logo=Postwoman"/>
|
||||
</a>
|
||||
<br/>
|
||||
<sub>
|
||||
Custom
|
||||
</sub>
|
||||
</td>
|
||||
<td>
|
||||
<code>[](https://postwoman.io)</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" width="200px">
|
||||
<a href="https://postwoman.io">
|
||||
<br/>
|
||||
<img src="https://img.shields.io/badge/your_text-Postwoman-hex_color_code?logo=Postwoman"/>
|
||||
</a>
|
||||
<br/>
|
||||
<sub>
|
||||
Customize
|
||||
</sub>
|
||||
</td>
|
||||
<td>
|
||||
<code>[](https://postwoman.io)</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div align="center">
|
||||
<br>
|
||||
<a href="https://postwoman.io"><img src="https://raw.githubusercontent.com/liyasthomas/templates/master/assets/logo.gif" alt="Postwoman.io" width="200"></a>
|
||||
<br>
|
||||
<h3>Happy Coding ❤︎</h3>
|
||||
</div>
|
||||
|
||||
@@ -4,11 +4,11 @@ Thanks for your interest in helping translating the software!
|
||||
|
||||
## Starting a translation
|
||||
|
||||
Before you start working on a translation, look through the [open pull requests](https://github.com/liyasthomas/postwoman/pulls) to see if anyone else is already working on one for your language.
|
||||
Before you start working on a translation, look through the [open pull requests](https://github.com/hoppscotch/hoppscotch/pulls) to see if anyone else is already working on one for your language.
|
||||
|
||||
If there's not, then today is your day to lead this effort! Here's how to start:
|
||||
|
||||
1. [Fork this repository](https://github.com/liyasthomas/postwoman/fork)
|
||||
1. [Fork this repository](https://github.com/hoppscotch/hoppscotch/fork)
|
||||
2. Create a new branch for your translation work e.g. `es`.
|
||||
3. Copy `lang/en-US.json` to your target language file e.g. `lang/es-ES.json` and translate all the strings.
|
||||
4. Add your language entry to `nuxt.config.js`.
|
||||
@@ -28,7 +28,7 @@ If there's not, then today is your day to lead this effort! Here's how to start:
|
||||
code: 'es',
|
||||
name: 'Español',
|
||||
iso: 'es-ES',
|
||||
file: 'es-ES.js'
|
||||
file: 'es-ES.json'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -37,7 +37,7 @@ If there's not, then today is your day to lead this effort! Here's how to start:
|
||||
5. Save & commit changes.
|
||||
6. Send a pull request. (You may send a pull request before all steps above are complete: e.g., you may want to ask for help with translations, or getting tests to pass. However your pull request will not be merged until all steps above are complete.)
|
||||
|
||||
Completing an initial translation of the whole site is a fairly large task. One way to break that task up is to work with other translators through pull requests on your fork. You can also [add collaborators to your fork](https://help.github.com/en/github/setting-up-and-managing-your-github-user-account/inviting-collaborators-to-a-personal-repository) if you'd like to inivte other translators to commit directly to your fork and share responsibility for merging pull requests.
|
||||
Completing an initial translation of the whole site is a fairly large task. One way to break that task up is to work with other translators through pull requests on your fork. You can also [add collaborators to your fork](https://help.github.com/en/github/setting-up-and-managing-your-github-user-account/inviting-collaborators-to-a-personal-repository) if you'd like to invite other translators to commit directly to your fork and share responsibility for merging pull requests.
|
||||
|
||||
## Updating a translation
|
||||
|
||||
|
||||
1
__mocks__/svgMock.js
Normal file
@@ -0,0 +1 @@
|
||||
export default {}
|
||||
@@ -1,7 +1,5 @@
|
||||
# ASSETS
|
||||
|
||||
**This directory is not required, you can delete it if you don't want to use it.**
|
||||
|
||||
This directory contains your un-compiled assets such as LESS, SASS, or JavaScript.
|
||||
|
||||
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked).
|
||||
|
||||
259
assets/css/fonts.css
Normal file
@@ -0,0 +1,259 @@
|
||||
/* fallback */
|
||||
@font-face {
|
||||
font-family: "Material Icons";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Material_Icons-400-fallback1.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* devanagari */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-400-devanagari2.woff2") format("woff2");
|
||||
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8,
|
||||
U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-400-latin-ext3.woff2") format("woff2");
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
||||
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-400-latin4.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
/* devanagari */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-500-devanagari5.woff2") format("woff2");
|
||||
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8,
|
||||
U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-500-latin-ext6.woff2") format("woff2");
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
||||
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-500-latin7.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
/* devanagari */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-600-devanagari8.woff2") format("woff2");
|
||||
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8,
|
||||
U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-600-latin-ext9.woff2") format("woff2");
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
||||
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-600-latin10.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
/* devanagari */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-700-devanagari11.woff2") format("woff2");
|
||||
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8,
|
||||
U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-700-latin-ext12.woff2") format("woff2");
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
||||
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-700-latin13.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
/* devanagari */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-800-devanagari14.woff2") format("woff2");
|
||||
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8,
|
||||
U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-800-latin-ext15.woff2") format("woff2");
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
||||
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-800-latin16.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Roboto_Mono-400-cyrillic-ext17.woff2") format("woff2");
|
||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F,
|
||||
U+FE2E-FE2F;
|
||||
}
|
||||
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Roboto_Mono-400-cyrillic18.woff2") format("woff2");
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Roboto_Mono-400-greek19.woff2") format("woff2");
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Roboto_Mono-400-vietnamese20.woff2") format("woff2");
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1,
|
||||
U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Roboto_Mono-400-latin-ext21.woff2") format("woff2");
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
||||
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Roboto_Mono-400-latin22.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
font-family: "Material Icons"; /* stylelint-disable-line font-family-no-missing-generic-family-keyword */
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
direction: ltr;
|
||||
-webkit-font-feature-settings: "liga";
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
// @import url("https://fonts.googleapis.com/css?family=Poppins:500,700|Roboto+Mono:400&display=swap");
|
||||
// @import url("https://fonts.googleapis.com/icon?family=Material+Icons&display=swap");
|
||||
|
||||
/* Material Design Icons */
|
||||
@font-face {
|
||||
font-family: "Material Icons";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
// Do not use font-display: swap for the icon font - it looks really bad when the page
|
||||
// loads.
|
||||
font-display: block;
|
||||
src: url("~static/fonts/material-icons-v52.woff2") format("woff2");
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
font-family: "Material Icons";
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
direction: ltr;
|
||||
-webkit-font-feature-settings: "liga";
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-feature-settings: "liga";
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* poppins-500 - latin */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: local("Poppins Medium"), local("Poppins-Medium"),
|
||||
url("~static/fonts/poppins-v9-latin-500.woff2") format("woff2"),
|
||||
url("~static/fonts/poppins-v9-latin-500.woff") format("woff");
|
||||
}
|
||||
|
||||
/* poppins-700 - latin */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: local("Poppins Bold"), local("Poppins-Bold"),
|
||||
url("~static/fonts/poppins-v9-latin-700.woff2") format("woff2"),
|
||||
url("~static/fonts/poppins-v9-latin-700.woff") format("woff");
|
||||
}
|
||||
|
||||
/* roboto-mono-regular - latin */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: local("Roboto Mono"), local("RobotoMono-Regular"),
|
||||
url("~static/fonts/roboto-mono-v7-latin-regular.woff2") format("woff2"),
|
||||
url("~static/fonts/roboto-mono-v7-latin-regular.woff") format("woff");
|
||||
}
|
||||
@@ -1,784 +0,0 @@
|
||||
$responsiveWidth: 768px;
|
||||
|
||||
::selection {
|
||||
background-color: var(--ac-color);
|
||||
color: var(--act-color);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 4px;
|
||||
background-color: var(--bg-dark-color);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 4px;
|
||||
background-color: var(--fg-light-color);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--fg-color);
|
||||
}
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: var(--fg-light-color);
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
outline: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
color: var(--fg-color);
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
font-family: "Poppins", "Roboto", "Noto", sans-serif;
|
||||
line-height: 1.5;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-touch-callout: none;
|
||||
user-select: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
scroll-behavior: smooth;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
body.afterLoad {
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
body.sticky-footer footer {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
a {
|
||||
display: inline-flex;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
&.link {
|
||||
color: var(--ac-color);
|
||||
}
|
||||
}
|
||||
|
||||
header,
|
||||
footer {
|
||||
& > div {
|
||||
display: flex;
|
||||
padding: 16px 8px;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.page-enter-active,
|
||||
.page-leave-active,
|
||||
.layout-enter-active,
|
||||
.layout-leave-active {
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.page-enter,
|
||||
.page-leave-active,
|
||||
.layout-enter,
|
||||
.layout-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
.wrapper .page {
|
||||
min-height: calc(100vh - 153px);
|
||||
}
|
||||
|
||||
.header,
|
||||
.content,
|
||||
.columns,
|
||||
.footer {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nav-first,
|
||||
.sticky-inner {
|
||||
display: flex;
|
||||
order: 1;
|
||||
flex-flow: column;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
flex: 1;
|
||||
order: 2;
|
||||
position: relative;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h3.title {
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
p {
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-bottom: 1px dashed var(--brd-color);
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
$bgcolor: var(--tt-color);
|
||||
$fgcolor: var(--fg-color);
|
||||
display: block !important;
|
||||
z-index: 10000;
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
.tooltip-inner {
|
||||
background: $bgcolor;
|
||||
color: $fgcolor;
|
||||
border-radius: 8px;
|
||||
padding: 8px 16px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 4px 24px rgba(black, 0.1);
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
position: absolute;
|
||||
margin: 5px;
|
||||
border-color: $bgcolor;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&[x-placement^="top"] {
|
||||
margin-bottom: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 5px 5px 0 5px;
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
bottom: -5px;
|
||||
left: calc(50% - 5px);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="bottom"] {
|
||||
margin-top: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 0 5px 5px 5px;
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-top-color: transparent !important;
|
||||
top: -5px;
|
||||
left: calc(50% - 5px);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="right"] {
|
||||
margin-left: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 5px 5px 5px 0;
|
||||
border-left-color: transparent !important;
|
||||
border-top-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
left: -5px;
|
||||
top: calc(50% - 5px);
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="left"] {
|
||||
margin-right: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 5px 0 5px 5px;
|
||||
border-top-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
right: -5px;
|
||||
top: calc(50% - 5px);
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.popover {
|
||||
.wrapper {
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.popover-inner {
|
||||
background: $bgcolor;
|
||||
color: $fgcolor;
|
||||
padding: 4px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 5px 30px rgba(black, 0.1);
|
||||
max-height: 256px;
|
||||
overflow: auto;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
button {
|
||||
justify-content: start;
|
||||
}
|
||||
}
|
||||
|
||||
.popover-arrow {
|
||||
border-color: $bgcolor;
|
||||
}
|
||||
}
|
||||
|
||||
&[aria-hidden="true"] {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s, visibility 0.15s;
|
||||
}
|
||||
|
||||
&[aria-hidden="false"] {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
}
|
||||
|
||||
.info:not(.toasted) {
|
||||
margin-left: 4px;
|
||||
color: var(--fg-light-color);
|
||||
|
||||
.material-icons {
|
||||
vertical-align: middle;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.bg-color {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 4px;
|
||||
padding: 6px 16px;
|
||||
border-radius: 8px;
|
||||
background-color: var(--ac-color);
|
||||
color: var(--act-color);
|
||||
font-size: 16px;
|
||||
font-family: "Poppins", "Roboto", "Noto", sans-serif;
|
||||
font-weight: 700;
|
||||
transition: all 0.2s ease-in-out;
|
||||
fill: var(--act-color);
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
display: inline-flex;
|
||||
margin-left: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&:not([disabled]):hover,
|
||||
&:not([disabled]):active,
|
||||
&:not([disabled]):focus {
|
||||
color: var(--act-color);
|
||||
fill: var(--act-color);
|
||||
box-shadow: inset 0 0 0 2px var(--fg-color);
|
||||
}
|
||||
|
||||
&.icon {
|
||||
background-color: transparent;
|
||||
color: var(--fg-light-color);
|
||||
fill: var(--fg-light-color);
|
||||
border-radius: 8px;
|
||||
|
||||
&:not([disabled]):hover,
|
||||
&:not([disabled]):active,
|
||||
&:not([disabled]):focus {
|
||||
color: var(--fg-color);
|
||||
fill: var(--fg-color);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.primary {
|
||||
color: var(--ac-color);
|
||||
|
||||
&:not([disabled]):hover,
|
||||
&:not([disabled]):active,
|
||||
&:not([disabled]):focus {
|
||||
background-color: var(--ac-color);
|
||||
color: var(--act-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes beat {
|
||||
30% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.material-icons:active {
|
||||
animation: beat 0.5s forwards 1;
|
||||
}
|
||||
|
||||
fieldset:target,
|
||||
section:target {
|
||||
animation: highlight 2s ease;
|
||||
}
|
||||
|
||||
@keyframes highlight {
|
||||
50% {
|
||||
box-shadow: 0 0 0 2px var(--ac-color);
|
||||
}
|
||||
}
|
||||
|
||||
input[type="file"],
|
||||
input[type="radio"],
|
||||
.hide-on-large-screen,
|
||||
#installPWA,
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.method,
|
||||
kbd,
|
||||
select,
|
||||
input,
|
||||
textarea,
|
||||
pre,
|
||||
code {
|
||||
display: inline-flex;
|
||||
margin: 4px;
|
||||
padding: 8px;
|
||||
border-radius: 8px;
|
||||
background-color: var(--bg-dark-color);
|
||||
color: var(--fg-color);
|
||||
font-size: 16px;
|
||||
font-family: "Roboto Mono", monospace;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
transition: all 0.2s ease-in-out;
|
||||
user-select: text;
|
||||
width: calc(100% - 8px);
|
||||
resize: vertical;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&:not([readonly]):not(.ace_editor):hover,
|
||||
&:not([readonly]):not(.ace_editor):active,
|
||||
&:not([readonly]):not(.ace_editor):focus {
|
||||
box-shadow: inset 0 0 0 2px var(--fg-light-color);
|
||||
}
|
||||
}
|
||||
|
||||
.method {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
box-shadow: inset 0 0 0 2px var(--fg-light-color);
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
pre.ace_editor {
|
||||
font-family: "Roboto Mono", monospace;
|
||||
font-weight: 400;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
kbd,
|
||||
code,
|
||||
pre {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.select-wrapper {
|
||||
position: relative;
|
||||
|
||||
input {
|
||||
text-transform: uppercase;
|
||||
min-width: 128px;
|
||||
}
|
||||
|
||||
.trigger {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:after {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
content: "\e313";
|
||||
font-family: "Material Icons";
|
||||
top: 14px;
|
||||
right: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
height: 37px;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
&::-ms-expand {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
option {
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
display: none;
|
||||
|
||||
&,
|
||||
& + label {
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
|
||||
&:before {
|
||||
content: "\2714";
|
||||
border: 1px solid var(--fg-color);
|
||||
border-radius: 8px;
|
||||
display: inline-flex;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 8px 8px 8px 0;
|
||||
color: transparent;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
&:checked + label:before {
|
||||
background-color: var(--ac-color);
|
||||
border-color: var(--ac-color);
|
||||
color: var(--act-color);
|
||||
}
|
||||
}
|
||||
|
||||
.error:not(input),
|
||||
.disabled:not(input),
|
||||
[disabled] {
|
||||
background-color: var(--err-color);
|
||||
color: var(--fg-light-color);
|
||||
fill: var(--fg-light-color);
|
||||
cursor: not-allowed;
|
||||
|
||||
&.icon {
|
||||
color: var(--err-color);
|
||||
fill: var(--err-color);
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
padding: 4px;
|
||||
color: var(--fg-light-color);
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
display: flex;
|
||||
margin: 4px 0 4px;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
|
||||
ul,
|
||||
ol {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
ul li,
|
||||
ol li {
|
||||
display: inline-flex;
|
||||
flex-flow: column nowrap;
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
|
||||
&.shrink {
|
||||
flex-grow: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.flex-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-grow: 1;
|
||||
flex-direction: row;
|
||||
|
||||
* {
|
||||
display: inline-flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.show-on-small-screen {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.show-on-large-screen {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.info-response {
|
||||
color: #ffeb3b;
|
||||
}
|
||||
|
||||
.success-response {
|
||||
color: #4bb543;
|
||||
}
|
||||
|
||||
.redir-response {
|
||||
color: #ff5722;
|
||||
}
|
||||
|
||||
.cl-error-response {
|
||||
color: #a63232;
|
||||
}
|
||||
|
||||
.sv-error-response {
|
||||
color: #b71c1c;
|
||||
}
|
||||
|
||||
.missing-data-response {
|
||||
background-color: var(--err-color);
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: "Roboto Mono", monospace;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
#response-details-wrapper {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 8px;
|
||||
|
||||
textarea {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.covers-response {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: white;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#send {
|
||||
&.show {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
bottom: 86px;
|
||||
left: 50%;
|
||||
z-index: 10001;
|
||||
transform: translateX(-50%);
|
||||
box-shadow: 0 4px 24px rgba(black, 0.2);
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.toasted-container .toasted {
|
||||
justify-content: flex-start !important;
|
||||
}
|
||||
|
||||
.toasted.info {
|
||||
background-color: var(--ac-color) !important;
|
||||
color: var(--act-color) !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
.toasted.bubble .action {
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
.toasted .action {
|
||||
margin-left: auto !important;
|
||||
}
|
||||
|
||||
.page-columns {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-flow: column;
|
||||
}
|
||||
|
||||
.inner-left {
|
||||
display: flex;
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.inner-right {
|
||||
display: flex;
|
||||
width: 30%;
|
||||
order: 2;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
@media (max-width: $responsiveWidth) {
|
||||
.content,
|
||||
.columns {
|
||||
flex-flow: column;
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 0 8px 68px;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
ul li,
|
||||
ol li {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.hide-on-small-screen {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hide-on-large-screen,
|
||||
.show-on-small-screen {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.sticky-inner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.inner-left {
|
||||
order: 0;
|
||||
}
|
||||
|
||||
.inner-right {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.toasted-container {
|
||||
margin-bottom: 68px;
|
||||
}
|
||||
}
|
||||
|
||||
.toasted-ad {
|
||||
background-color: #fefefe;
|
||||
color: #121212;
|
||||
padding: 16px !important;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.action {
|
||||
text-transform: none !important;
|
||||
background-color: #121212;
|
||||
color: #fefefe;
|
||||
padding: 12px 16px !important;
|
||||
font-weight: 500 !important;
|
||||
font-size: 16px !important;
|
||||
border-radius: 8px;
|
||||
margin: 0 !important;
|
||||
margin-left: 8px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.virtual-list {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.truncate {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
6
assets/css/tailwind.css
Normal file
@@ -0,0 +1,6 @@
|
||||
/* purgecss start ignore */
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
|
||||
/* purgecss end ignore */
|
||||
@tailwind utilities;
|
||||
BIN
assets/fonts/Material_Icons-400-fallback1.woff2
Normal file
BIN
assets/fonts/Poppins-400-devanagari2.woff2
Normal file
BIN
assets/fonts/Poppins-400-latin-ext3.woff2
Normal file
BIN
assets/fonts/Poppins-400-latin4.woff2
Normal file
BIN
assets/fonts/Poppins-500-devanagari5.woff2
Normal file
BIN
assets/fonts/Poppins-500-latin-ext6.woff2
Normal file
BIN
assets/fonts/Poppins-500-latin7.woff2
Normal file
BIN
assets/fonts/Poppins-600-devanagari8.woff2
Normal file
BIN
assets/fonts/Poppins-600-latin-ext9.woff2
Normal file
BIN
assets/fonts/Poppins-600-latin10.woff2
Normal file
BIN
assets/fonts/Poppins-700-devanagari11.woff2
Normal file
BIN
assets/fonts/Poppins-700-latin-ext12.woff2
Normal file
BIN
assets/fonts/Poppins-700-latin13.woff2
Normal file
BIN
assets/fonts/Poppins-800-devanagari14.woff2
Normal file
BIN
assets/fonts/Poppins-800-latin-ext15.woff2
Normal file
BIN
assets/fonts/Poppins-800-latin16.woff2
Normal file
BIN
assets/fonts/Roboto_Mono-400-cyrillic-ext17.woff2
Normal file
BIN
assets/fonts/Roboto_Mono-400-cyrillic18.woff2
Normal file
BIN
assets/fonts/Roboto_Mono-400-greek19.woff2
Normal file
BIN
assets/fonts/Roboto_Mono-400-latin-ext21.woff2
Normal file
BIN
assets/fonts/Roboto_Mono-400-latin22.woff2
Normal file
BIN
assets/fonts/Roboto_Mono-400-vietnamese20.woff2
Normal file
BIN
assets/images/Paw-Logo-for-Hoppscotch.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
assets/images/Simplescraper.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
assets/images/Simplescraper_dark.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 7.4 KiB |
230
assets/images/appwrite-banner.svg
Normal file
|
After Width: | Height: | Size: 3.5 MiB |
8
assets/images/appwrite-icon.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg width="198" height="172" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="none" d="M-1-1h200v174H-1z"/>
|
||||
<g>
|
||||
<path fill="#f02e65" d="M197.289 88c0 35.899-29.101 65-65 65-16.675 0-31.883-6.279-43.389-16.601 18.433-8.298 31.266-26.827 31.266-48.353 0-21.553-12.865-40.101-31.335-48.384C100.346 29.304 115.581 23 132.289 23c35.899 0 65 29.101 65 65z"/>
|
||||
<path fill="#f02e65" d="M106.306 36.116a65 65 0 10-78.307 103.769 65 65 0 1078.307-103.77v.001zm-7.229 9.578a53 53 0 01-63.85 84.612 53 53 0 0163.85-84.612z"/>
|
||||
<path fill="#f02e65" d="M68.894 65.511c-.078.192-1.072 4.095-2.142 8.725-1.111 4.63-2.871 11.938-3.864 16.262-1.915 7.92-3.063 13.124-3.063 13.813 0 .19 1.187.345 2.64.345h2.641l1.185-5.282c.69-2.869 2.221-9.451 3.445-14.616 1.225-5.166 2.716-11.441 3.291-13.967.573-2.526 1.147-4.82 1.263-5.088.115-.344-.537-.458-2.526-.458-1.493 0-2.795.114-2.87.266zM48.345 82.079l-3.52 3.827 1.034 1.224c.572.688 2.143 2.411 3.482 3.827l2.449 2.601h6.964l-3.29-3.559c-1.8-1.911-3.292-3.749-3.292-3.978 0-.268 1.378-1.989 3.062-3.826 1.683-1.874 3.061-3.483 3.061-3.674 0-.153-1.454-.268-3.214-.268h-3.176l-3.56 3.826zm26.785-3.597c0 .116.651.842 1.453 1.646 2.987 2.984 5.091 5.511 4.976 6.007-.076.269-1.531 2.066-3.29 3.941l-3.175 3.482h3.557l3.559-.038 3.251-3.558c1.8-1.988 3.253-3.751 3.253-3.98 0-.19-1.53-1.989-3.444-4.016l-3.442-3.713h-3.331c-1.875 0-3.367.115-3.367.229z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
113
assets/images/ossc-banner.svg
Normal file
|
After Width: | Height: | Size: 3.6 MiB |
BIN
assets/images/pipedream.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
32
assets/js/regex.worker.js
Normal file
@@ -0,0 +1,32 @@
|
||||
function generateREForProtocol(protocol) {
|
||||
return [
|
||||
new RegExp(
|
||||
`${protocol}(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`
|
||||
),
|
||||
new RegExp(
|
||||
`${protocol}(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9/])$`
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
const ws = generateREForProtocol("^(wss?:\\/\\/)?")
|
||||
const sse = generateREForProtocol("^(https?:\\/\\/)?")
|
||||
const socketio = generateREForProtocol("^((wss?:\\/\\/)|(https?:\\/\\/))?")
|
||||
const regex = { ws, sse, socketio }
|
||||
|
||||
// type = ws/sse/socketio
|
||||
async function validator(type, url) {
|
||||
console.time(`validator ${url}`)
|
||||
const [res1, res2] = await Promise.all([
|
||||
regex[type][0].test(url),
|
||||
regex[type][1].test(url),
|
||||
])
|
||||
console.timeEnd(`validator ${url}`)
|
||||
return res1 || res2
|
||||
}
|
||||
|
||||
onmessage = async ({ data }) => {
|
||||
const { type, url } = data
|
||||
const result = await validator(type, url)
|
||||
postMessage({ type, url, result })
|
||||
}
|
||||
15
assets/md/docs.md
Normal file
@@ -0,0 +1,15 @@
|
||||
**Table of Contents**
|
||||
|
||||
{{#collections}}
|
||||
{{>folderContents}}
|
||||
{{/collections}}
|
||||
|
||||
{{#collections}}
|
||||
|
||||
{{>folderBody}}
|
||||
|
||||
{{/collections}}
|
||||
|
||||
---
|
||||
|
||||
Made with [Hoppscotch](https://github.com/hoppscotch/hoppscotch)
|
||||
113
assets/md/folderBody.md
Normal file
@@ -0,0 +1,113 @@
|
||||
{{nestingLevel}} {{name}}
|
||||
|
||||
{{#requests}}
|
||||
|
||||
{{nestingLevel}} Request: {{name}}
|
||||
|
||||
**Method**: {{method}}
|
||||
|
||||
**Request URL**:
|
||||
|
||||
```
|
||||
{{{url}}}{{{path}}}
|
||||
```
|
||||
|
||||
{{#isHeaders}}
|
||||
**Headers**:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
{{#headers}}
|
||||
<tr>
|
||||
<td>{{{key}}}</td>
|
||||
<td>`{{{value}}}`</td>
|
||||
</tr>
|
||||
{{/headers}}
|
||||
</table>
|
||||
{{/isHeaders}}
|
||||
|
||||
{{#isParams}}
|
||||
**Parameters**:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>type</th>
|
||||
<th>Key</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
{{#params}}
|
||||
<tr>
|
||||
<td>{{type}}</td>
|
||||
<td>{{{key}}}</td>
|
||||
<td>{{{value}}}</td>
|
||||
</tr>
|
||||
{{/params}}
|
||||
</table>
|
||||
{{/isParams}}
|
||||
|
||||
{{#isAuth}}
|
||||
**Authentication Type**: {{{auth}}}
|
||||
{{/isAuth}}
|
||||
|
||||
{{#bearerToken}}
|
||||
**Bearer Token**: `{{{.}}}`
|
||||
{{/bearerToken}}
|
||||
|
||||
{{#isAuthBasic}}
|
||||
Username: `{{{httpUser}}}`
|
||||
Password: `{{{httpPassword}}}`
|
||||
{{/isAuthBasic}}
|
||||
|
||||
{{#isRawParams}}
|
||||
**Raw Parameters**:
|
||||
|
||||
```json
|
||||
{{{rawParams}}}
|
||||
```
|
||||
|
||||
{{/isRawParams}}
|
||||
|
||||
{{#contentType}}
|
||||
**Content Type**: `{{{contentType}}}`
|
||||
{{/contentType}}
|
||||
|
||||
{{#isPreRequestScript}}
|
||||
**Pre Request Script**:
|
||||
|
||||
```js
|
||||
{
|
||||
{
|
||||
{
|
||||
preRequestScript
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
{{/isPreRequestScript}}
|
||||
|
||||
{{#isTestScript}}
|
||||
**Test Script**:
|
||||
|
||||
```js
|
||||
{
|
||||
{
|
||||
{
|
||||
testScript
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
{{/isTestScript}}
|
||||
|
||||
{{/requests}}
|
||||
|
||||
{{#folders}}
|
||||
|
||||
{{> folderBody }}
|
||||
|
||||
{{/folders}}
|
||||
4
assets/md/folderContents.md
Normal file
@@ -0,0 +1,4 @@
|
||||
{{{id}}} <a href="#{{ref}}"> {{name}} </a> <br>
|
||||
{{#folders}}
|
||||
{{> folderContents}}
|
||||
{{/folders}}
|
||||
813
assets/scss/styles.scss
Normal file
@@ -0,0 +1,813 @@
|
||||
$responsiveWidth: 768px;
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
:root {
|
||||
@apply antialiased;
|
||||
|
||||
font-variant-ligatures: common-ligatures;
|
||||
}
|
||||
|
||||
::selection {
|
||||
@apply bg-acColor;
|
||||
@apply text-actColor;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
@apply h-1;
|
||||
@apply w-2;
|
||||
|
||||
&:hover {
|
||||
@apply bg-bgDarkColor;
|
||||
}
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
@apply bg-fgLightColor;
|
||||
|
||||
&:hover {
|
||||
@apply bg-fgColor;
|
||||
}
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
@apply text-fgLightColor;
|
||||
@apply opacity-25;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-bgColor;
|
||||
@apply text-fgColor;
|
||||
@apply text-base;
|
||||
@apply font-medium;
|
||||
@apply select-none;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-touch-callout: none;
|
||||
}
|
||||
|
||||
body.afterLoad {
|
||||
@apply transition-colors;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
|
||||
body.sticky-footer footer {
|
||||
@apply opacity-25;
|
||||
}
|
||||
|
||||
.page-enter-active,
|
||||
.page-leave-active,
|
||||
.layout-enter-active,
|
||||
.layout-leave-active {
|
||||
@apply transition-opacity;
|
||||
@apply duration-150;
|
||||
}
|
||||
|
||||
.page-enter,
|
||||
.page-leave-active,
|
||||
.layout-enter,
|
||||
.layout-leave-active {
|
||||
@apply opacity-0;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply inline-flex;
|
||||
@apply text-current;
|
||||
@apply no-underline;
|
||||
@apply outline-none;
|
||||
|
||||
&.link {
|
||||
@apply text-acColor;
|
||||
}
|
||||
}
|
||||
|
||||
header,
|
||||
footer {
|
||||
& > div {
|
||||
@apply flex;
|
||||
@apply py-2;
|
||||
@apply px-2;
|
||||
@apply w-full;
|
||||
@apply items-center;
|
||||
@apply justify-between;
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
@apply min-h-screen;
|
||||
@apply flex;
|
||||
@apply flex-col;
|
||||
@apply flex-nowrap;
|
||||
}
|
||||
|
||||
.wrapper .page {
|
||||
min-height: calc(100vh - 153px);
|
||||
}
|
||||
|
||||
.header,
|
||||
.content,
|
||||
.columns,
|
||||
.footer {
|
||||
@apply flex;
|
||||
@apply flex-1;
|
||||
}
|
||||
|
||||
.nav-first,
|
||||
.sticky-inner {
|
||||
@apply flex;
|
||||
@apply order-1;
|
||||
@apply flex-col;
|
||||
@apply sticky;
|
||||
@apply top-0;
|
||||
@apply items-start;
|
||||
@apply items-stretch;
|
||||
@apply h-full;
|
||||
}
|
||||
|
||||
main {
|
||||
@apply flex;
|
||||
@apply flex-col;
|
||||
@apply flex-1;
|
||||
@apply order-2;
|
||||
@apply relative;
|
||||
@apply px-4;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
@apply flex;
|
||||
@apply items-center;
|
||||
@apply m-0;
|
||||
@apply font-bold;
|
||||
}
|
||||
|
||||
h3.title {
|
||||
@apply m-2;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-sm;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply border-b;
|
||||
@apply border-dashed;
|
||||
@apply border-brdColor;
|
||||
@apply my-4;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
@apply z-50;
|
||||
@apply outline-none;
|
||||
|
||||
.tooltip-inner {
|
||||
@apply rounded-lg;
|
||||
@apply px-4;
|
||||
@apply py-2;
|
||||
@apply text-xs;
|
||||
@apply font-medium;
|
||||
@apply shadow-lg;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
@apply bg-ttColor;
|
||||
@apply text-fgColor;
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
@apply h-0;
|
||||
@apply w-0;
|
||||
@apply border-solid;
|
||||
@apply absolute;
|
||||
@apply m-2;
|
||||
@apply border-ttColor;
|
||||
@apply z-30;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
|
||||
&[x-placement^="top"] {
|
||||
@apply mb-0;
|
||||
|
||||
.tooltip-arrow {
|
||||
@apply mt-0;
|
||||
@apply mb-0;
|
||||
|
||||
border-width: 5px 5px 0 5px;
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
bottom: -5px;
|
||||
left: calc(50% - 5px);
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="bottom"] {
|
||||
@apply mt-0;
|
||||
|
||||
.tooltip-arrow {
|
||||
@apply mt-0;
|
||||
@apply mb-0;
|
||||
|
||||
border-width: 0 5px 5px 5px;
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-top-color: transparent !important;
|
||||
top: -5px;
|
||||
left: calc(50% - 5px);
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="right"] {
|
||||
@apply ml-0;
|
||||
|
||||
.tooltip-arrow {
|
||||
@apply ml-0;
|
||||
@apply mr-0;
|
||||
|
||||
border-width: 5px 5px 5px 0;
|
||||
border-left-color: transparent !important;
|
||||
border-top-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
left: -5px;
|
||||
top: calc(50% - 5px);
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="left"] {
|
||||
@apply mr-0;
|
||||
|
||||
.tooltip-arrow {
|
||||
@apply ml-0;
|
||||
@apply mr-0;
|
||||
|
||||
border-width: 5px 0 5px 5px;
|
||||
border-top-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
right: -5px;
|
||||
top: calc(50% - 5px);
|
||||
}
|
||||
}
|
||||
|
||||
&.popover {
|
||||
.wrapper {
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.popover-inner {
|
||||
@apply bg-ttColor;
|
||||
@apply text-fgColor;
|
||||
@apply text-base;
|
||||
@apply p-2;
|
||||
@apply rounded-lg;
|
||||
@apply overflow-auto;
|
||||
@apply shadow-lg;
|
||||
|
||||
max-height: 256px;
|
||||
min-width: 128px;
|
||||
|
||||
button {
|
||||
@apply flex-1;
|
||||
@apply m-0;
|
||||
@apply p-2;
|
||||
@apply justify-start;
|
||||
@apply text-left;
|
||||
}
|
||||
|
||||
div {
|
||||
@apply flex;
|
||||
@apply items-stretch;
|
||||
@apply flex-col;
|
||||
}
|
||||
}
|
||||
|
||||
.popover-arrow {
|
||||
@apply border-ttColor;
|
||||
}
|
||||
}
|
||||
|
||||
&[aria-hidden="true"] {
|
||||
@apply invisible;
|
||||
@apply opacity-0;
|
||||
@apply transition-opacity;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
|
||||
&[aria-hidden="false"] {
|
||||
@apply visible;
|
||||
@apply opacity-100;
|
||||
@apply transition-opacity;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
}
|
||||
|
||||
.info:not(.toasted) {
|
||||
@apply m-4;
|
||||
@apply text-fgLightColor;
|
||||
|
||||
.material-icons {
|
||||
@apply align-middle;
|
||||
@apply mr-2;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
@apply inline-flex;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply p-4;
|
||||
@apply bg-acColor;
|
||||
@apply text-actColor;
|
||||
@apply font-bold;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
@apply fill-current;
|
||||
@apply cursor-pointer;
|
||||
@apply outline-none;
|
||||
@apply border-none;
|
||||
|
||||
span {
|
||||
@apply inline-flex;
|
||||
@apply ml-4;
|
||||
@apply text-left;
|
||||
}
|
||||
|
||||
&:not([disabled]):hover,
|
||||
&:not([disabled]):active,
|
||||
&:not([disabled]):focus {
|
||||
@apply text-actColor;
|
||||
@apply fill-current;
|
||||
@apply outline-none;
|
||||
|
||||
box-shadow: inset 0 0 0 2px var(--fg-color);
|
||||
}
|
||||
|
||||
&.icon {
|
||||
@apply bg-transparent;
|
||||
@apply text-fgLightColor;
|
||||
@apply fill-current;
|
||||
@apply outline-none;
|
||||
@apply border-none;
|
||||
@apply rounded-lg;
|
||||
|
||||
&:not([disabled]):hover,
|
||||
&:not([disabled]):active,
|
||||
&:not([disabled]):focus {
|
||||
@apply text-fgColor;
|
||||
@apply fill-current;
|
||||
@apply shadow-none;
|
||||
}
|
||||
}
|
||||
|
||||
&.primary {
|
||||
@apply text-acColor;
|
||||
@apply px-6;
|
||||
|
||||
&:not([disabled]):hover,
|
||||
&:not([disabled]):active,
|
||||
&:not([disabled]):focus {
|
||||
@apply bg-acColor;
|
||||
@apply text-actColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes beat {
|
||||
30% {
|
||||
@apply transform;
|
||||
@apply scale-90;
|
||||
}
|
||||
50% {
|
||||
@apply transform;
|
||||
@apply scale-110;
|
||||
}
|
||||
100% {
|
||||
@apply transform;
|
||||
@apply scale-100;
|
||||
}
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
&:active {
|
||||
animation: beat 0.5s forwards 1;
|
||||
}
|
||||
}
|
||||
|
||||
fieldset:target,
|
||||
section:target {
|
||||
animation: highlight 2s ease;
|
||||
}
|
||||
|
||||
@keyframes highlight {
|
||||
50% {
|
||||
box-shadow: 0 0 0 2px var(--ac-color);
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
@apply truncate;
|
||||
}
|
||||
|
||||
input[type="file"],
|
||||
input[type="radio"],
|
||||
#installPWA {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.show-on-large-screen {
|
||||
@apply flex;
|
||||
@apply flex-1;
|
||||
}
|
||||
|
||||
.method,
|
||||
.url-field,
|
||||
kbd,
|
||||
select,
|
||||
input,
|
||||
textarea,
|
||||
pre,
|
||||
code {
|
||||
@apply flex;
|
||||
@apply p-4;
|
||||
@apply bg-bgDarkColor;
|
||||
@apply text-fgColor;
|
||||
@apply font-mono;
|
||||
@apply font-normal;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
@apply select-text;
|
||||
@apply resize-y;
|
||||
@apply outline-none;
|
||||
@apply w-full;
|
||||
|
||||
&:not([readonly]):not(.ace_editor):hover,
|
||||
&:not([readonly]):not(.ace_editor):active,
|
||||
&:not([readonly]):not(.ace_editor):focus {
|
||||
box-shadow: inset 0 0 0 2px var(--fg-light-color);
|
||||
}
|
||||
}
|
||||
|
||||
.method {
|
||||
@apply cursor-pointer;
|
||||
@apply uppercase;
|
||||
@apply rounded-none;
|
||||
|
||||
min-width: 128px;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
box-shadow: inset 0 0 0 2px var(--fg-light-color);
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
@apply grid;
|
||||
}
|
||||
|
||||
pre.ace_editor {
|
||||
@apply font-mono;
|
||||
@apply font-normal;
|
||||
@apply z-0;
|
||||
@apply resize-none;
|
||||
}
|
||||
|
||||
kbd,
|
||||
code,
|
||||
pre {
|
||||
@apply w-auto;
|
||||
}
|
||||
|
||||
.select-wrapper {
|
||||
@apply relative;
|
||||
@apply w-full;
|
||||
|
||||
pre,
|
||||
input {
|
||||
@apply cursor-pointer;
|
||||
}
|
||||
|
||||
.trigger {
|
||||
@apply w-full;
|
||||
}
|
||||
|
||||
&::after {
|
||||
@apply inline-block;
|
||||
@apply absolute;
|
||||
@apply pointer-events-none;
|
||||
@apply font-icon;
|
||||
@apply text-fgLightColor;
|
||||
|
||||
content: "\e313";
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
@apply cursor-pointer;
|
||||
@apply appearance-none;
|
||||
|
||||
// height: 40px;
|
||||
|
||||
&::-ms-expand {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
|
||||
option {
|
||||
@apply bg-bgColor;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
@apply hidden;
|
||||
|
||||
&,
|
||||
& + label {
|
||||
@apply align-middle;
|
||||
@apply cursor-pointer;
|
||||
|
||||
&::before {
|
||||
@apply border;
|
||||
@apply border-fgColor;
|
||||
@apply rounded-lg;
|
||||
@apply inline-flex;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply text-transparent;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
|
||||
content: "\2714";
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin: 8px 8px 8px 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:checked + label::before {
|
||||
@apply bg-acColor;
|
||||
@apply border-acColor;
|
||||
@apply text-actColor;
|
||||
}
|
||||
}
|
||||
|
||||
.error:not(input),
|
||||
.disabled:not(input),
|
||||
[disabled] {
|
||||
@apply bg-errColor;
|
||||
@apply text-fgLightColor;
|
||||
@apply fill-current;
|
||||
@apply cursor-not-allowed;
|
||||
|
||||
&.icon {
|
||||
@apply text-errColor;
|
||||
@apply fill-current;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
@apply p-4;
|
||||
@apply text-fgLightColor;
|
||||
@apply text-sm;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
@apply flex;
|
||||
}
|
||||
|
||||
ul li,
|
||||
ol li {
|
||||
@apply inline-flex;
|
||||
@apply flex-col;
|
||||
@apply flex-nowrap;
|
||||
@apply flex-1;
|
||||
@apply justify-center;
|
||||
|
||||
&.shrink {
|
||||
@apply flex-grow-0;
|
||||
}
|
||||
}
|
||||
|
||||
.row-wrapper {
|
||||
@apply flex;
|
||||
@apply items-center;
|
||||
@apply justify-between;
|
||||
@apply flex-1;
|
||||
@apply flex-row;
|
||||
|
||||
span,
|
||||
div {
|
||||
@apply inline-flex;
|
||||
@apply flex-nowrap;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
}
|
||||
}
|
||||
|
||||
.info-response {
|
||||
@apply text-yellow-400;
|
||||
}
|
||||
|
||||
.success-response {
|
||||
@apply text-green-400;
|
||||
}
|
||||
|
||||
.redir-response {
|
||||
@apply text-pink-400;
|
||||
}
|
||||
|
||||
.cl-error-response {
|
||||
@apply text-red-400;
|
||||
}
|
||||
|
||||
.sv-error-response {
|
||||
@apply text-red-600;
|
||||
}
|
||||
|
||||
.missing-data-response {
|
||||
@apply text-fgLightColor;
|
||||
}
|
||||
|
||||
#response-details-wrapper {
|
||||
@apply relative;
|
||||
|
||||
textarea {
|
||||
@apply m-0;
|
||||
@apply w-full;
|
||||
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.covers-response {
|
||||
@apply absolute;
|
||||
@apply inset-0;
|
||||
@apply bg-white;
|
||||
@apply h-full;
|
||||
@apply w-full;
|
||||
}
|
||||
}
|
||||
|
||||
#send {
|
||||
@apply whitespace-nowrap;
|
||||
@apply outline-none;
|
||||
@apply border-none;
|
||||
|
||||
&.show {
|
||||
@apply flex;
|
||||
@apply fixed;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
@apply shadow-lg;
|
||||
@apply rounded-lg;
|
||||
|
||||
bottom: 86px;
|
||||
left: 50%;
|
||||
z-index: 10001;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
@apply flex;
|
||||
@apply rounded-lg;
|
||||
@apply w-full;
|
||||
}
|
||||
|
||||
.toasted-container .toasted {
|
||||
justify-content: space-between !important;
|
||||
}
|
||||
|
||||
.toasted.info {
|
||||
background-color: var(--ac-color) !important;
|
||||
color: var(--act-color) !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
.toasted.bubble .action {
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
.toasted .action {
|
||||
margin-left: auto !important;
|
||||
}
|
||||
|
||||
.page-columns {
|
||||
@apply flex;
|
||||
@apply flex-1;
|
||||
@apply flex-col;
|
||||
}
|
||||
|
||||
.inner-left {
|
||||
@apply flex;
|
||||
@apply order-1;
|
||||
}
|
||||
|
||||
.inner-right {
|
||||
@apply flex;
|
||||
@apply order-2;
|
||||
@apply ml-4;
|
||||
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
@media (max-width: $responsiveWidth) {
|
||||
.content,
|
||||
.columns {
|
||||
@apply flex-col;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 0 8px 68px;
|
||||
margin-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
@apply flex-col;
|
||||
@apply flex-nowrap;
|
||||
}
|
||||
|
||||
ul li,
|
||||
ol li {
|
||||
@apply flex;
|
||||
}
|
||||
|
||||
.hide-on-small-screen {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.sticky-inner {
|
||||
@apply relative;
|
||||
@apply w-full;
|
||||
}
|
||||
|
||||
.inner-left {
|
||||
order: 0;
|
||||
}
|
||||
|
||||
.inner-right {
|
||||
@apply ml-0;
|
||||
}
|
||||
|
||||
.toasted-container {
|
||||
margin-bottom: 68px;
|
||||
}
|
||||
}
|
||||
|
||||
.toasted-ad {
|
||||
@apply bg-gray-50;
|
||||
@apply text-gray-900;
|
||||
@apply font-bold;
|
||||
@apply text-sm;
|
||||
@apply rounded-lg;
|
||||
@apply shadow-lg;
|
||||
|
||||
padding: 16px !important;
|
||||
|
||||
.action {
|
||||
@apply bg-gray-50;
|
||||
@apply text-gray-900;
|
||||
@apply rounded-lg;
|
||||
@apply font-bold;
|
||||
|
||||
text-transform: none !important;
|
||||
padding: 12px 16px !important;
|
||||
font-size: 16px !important;
|
||||
margin: 0 !important;
|
||||
margin-left: 8px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.virtual-list {
|
||||
@apply overflow-auto;
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
/**
|
||||
Main Themes:
|
||||
- dark (default)
|
||||
- light
|
||||
- black
|
||||
- auto
|
||||
*/
|
||||
@mixin baseTheme {
|
||||
--font-sans: "Poppins", "sans-serif";
|
||||
--font-mono: "Roboto Mono", "monospace";
|
||||
--font-icon: "Material Icons";
|
||||
}
|
||||
|
||||
// Dark is the default theme variant.
|
||||
@mixin darkTheme {
|
||||
// Background color
|
||||
--bg-color: rgba(32, 33, 36, 1);
|
||||
@@ -22,14 +19,12 @@
|
||||
--brd-color: rgba(255, 255, 255, 0.05);
|
||||
// Error color
|
||||
--err-color: rgba(255, 255, 255, 0.05);
|
||||
// Acent color
|
||||
--ac-color: rgba(80, 250, 123, 1);
|
||||
// Tooltip color
|
||||
--tt-color: rgba(48, 48, 48, 1);
|
||||
// Editor theme
|
||||
--editor-theme: "twilight";
|
||||
// Active text color
|
||||
--act-color: rgba(32, 33, 36, 1);
|
||||
// Auto-complete color
|
||||
--atc-color: rgba(32, 33, 36, 1);
|
||||
// Tooltip color
|
||||
--tt-color: rgba(53, 53, 53, 1);
|
||||
}
|
||||
|
||||
@mixin lightTheme {
|
||||
@@ -47,14 +42,12 @@
|
||||
--brd-color: rgba(0, 0, 0, 0.1);
|
||||
// Error color
|
||||
--err-color: rgba(0, 0, 0, 0.1);
|
||||
// Acent color
|
||||
--ac-color: rgba(80, 250, 123, 1);
|
||||
// Tooltip color
|
||||
--tt-color: rgba(255, 255, 255, 1);
|
||||
// Editor theme
|
||||
--editor-theme: "iplastic";
|
||||
// Active text color
|
||||
--act-color: rgba(255, 255, 255, 1);
|
||||
// Auto-complete color
|
||||
--atc-color: rgba(255, 255, 255, 1);
|
||||
// Tooltip color
|
||||
--tt-color: rgba(220, 220, 220, 1);
|
||||
}
|
||||
|
||||
@mixin blackTheme {
|
||||
@@ -72,36 +65,101 @@
|
||||
--brd-color: rgba(255, 255, 255, 0.05);
|
||||
// Error color
|
||||
--err-color: rgba(255, 255, 255, 0.05);
|
||||
// Acent color
|
||||
--ac-color: rgba(80, 250, 123, 1);
|
||||
// Tooltip color
|
||||
--tt-color: rgba(32, 32, 32, 1);
|
||||
// Editor theme
|
||||
--editor-theme: "vibrant_ink";
|
||||
// Active text color
|
||||
--act-color: rgba(0, 0, 0, 1);
|
||||
// Auto-complete color
|
||||
--atc-color: rgba(0, 0, 0, 1);
|
||||
// Tooltip color
|
||||
--tt-color: rgba(18, 18, 18, 1);
|
||||
}
|
||||
|
||||
@mixin blueTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.blue.400");
|
||||
}
|
||||
|
||||
@mixin greenTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.green.400");
|
||||
}
|
||||
|
||||
@mixin tealTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.teal.400");
|
||||
}
|
||||
|
||||
@mixin indigoTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.indigo.400");
|
||||
}
|
||||
|
||||
@mixin purpleTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.purple.400");
|
||||
}
|
||||
|
||||
@mixin orangeTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.orange.400");
|
||||
}
|
||||
|
||||
@mixin pinkTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.pink.400");
|
||||
}
|
||||
|
||||
@mixin redTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.red.400");
|
||||
}
|
||||
|
||||
@mixin yellowTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.yellow.400");
|
||||
}
|
||||
|
||||
:root {
|
||||
@include baseTheme;
|
||||
@include darkTheme;
|
||||
@include greenTheme;
|
||||
}
|
||||
|
||||
:root.light {
|
||||
@include lightTheme;
|
||||
}
|
||||
|
||||
:root.dark {
|
||||
@include darkTheme;
|
||||
}
|
||||
|
||||
:root.black {
|
||||
@include blackTheme;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root.auto {
|
||||
@include darkTheme;
|
||||
}
|
||||
:root[data-accent="blue"] {
|
||||
@include blueTheme;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root.auto {
|
||||
@include lightTheme;
|
||||
}
|
||||
:root[data-accent="green"] {
|
||||
@include greenTheme;
|
||||
}
|
||||
:root[data-accent="teal"] {
|
||||
@include tealTheme;
|
||||
}
|
||||
:root[data-accent="indigo"] {
|
||||
@include indigoTheme;
|
||||
}
|
||||
:root[data-accent="purple"] {
|
||||
@include purpleTheme;
|
||||
}
|
||||
:root[data-accent="orange"] {
|
||||
@include orangeTheme;
|
||||
}
|
||||
:root[data-accent="pink"] {
|
||||
@include pinkTheme;
|
||||
}
|
||||
:root[data-accent="red"] {
|
||||
@include redTheme;
|
||||
}
|
||||
:root[data-accent="yellow"] {
|
||||
@include yellowTheme;
|
||||
}
|
||||
26
babel.config.js
Normal file
@@ -0,0 +1,26 @@
|
||||
function isBabelLoader(caller) {
|
||||
return caller && caller.name === "babel-loader"
|
||||
}
|
||||
|
||||
module.exports = function (api) {
|
||||
if (api.env("test") && !api.caller(isBabelLoader)) {
|
||||
return {
|
||||
plugins: [
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator",
|
||||
"@babel/plugin-proposal-optional-chaining",
|
||||
],
|
||||
presets: [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
targets: {
|
||||
node: "current",
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
56
build.js
@@ -1,56 +0,0 @@
|
||||
const axios = require("axios")
|
||||
const fs = require("fs")
|
||||
const { spawnSync } = require("child_process")
|
||||
const runCommand = (command, args) => spawnSync(command, args).stdout.toString().replace(/\n/g, "")
|
||||
|
||||
const FAIL_ON_ERROR = false
|
||||
const PW_BUILD_DATA_DIR = "./.postwoman"
|
||||
// const IS_DEV_MODE = process.argv.includes("--dev")
|
||||
|
||||
try {
|
||||
;(async () => {
|
||||
// Create the build data directory if it does not exist.
|
||||
if (!fs.existsSync(PW_BUILD_DATA_DIR)) {
|
||||
fs.mkdirSync(PW_BUILD_DATA_DIR)
|
||||
}
|
||||
|
||||
let version = {}
|
||||
// Get the current version name as the tag from Git.
|
||||
version.name =
|
||||
process.env.TRAVIS_TAG || runCommand("git", ["tag --sort=committerdate | tail -1"])
|
||||
|
||||
// FALLBACK: If version.name was unset, let's grab it from GitHub.
|
||||
if (!version.name) {
|
||||
version.name = (
|
||||
await axios
|
||||
.get("https://api.github.com/repos/liyasthomas/postwoman/releases")
|
||||
// If we can't get it from GitHub, we'll resort to getting it from package.json
|
||||
.catch((ex) => ({
|
||||
data: [
|
||||
{
|
||||
tag_name: require("./package.json").version,
|
||||
},
|
||||
],
|
||||
}))
|
||||
).data[0]["tag_name"]
|
||||
}
|
||||
|
||||
// Get the current version hash as the short hash from Git.
|
||||
// version.hash = runCommand("git", ["rev-parse", "--short", "HEAD"])
|
||||
// Get the 'variant' name as the branch, if it's not master.
|
||||
// version.variant =
|
||||
// process.env.TRAVIS_BRANCH ||
|
||||
// runCommand("git", ["branch"])
|
||||
// .split("* ")[1]
|
||||
// .split(" ")[0] + (IS_DEV_MODE ? " - DEV MODE" : "")
|
||||
// if (["", "master"].includes(version.variant)) {
|
||||
// delete version.variant
|
||||
// }
|
||||
|
||||
// Write version data into a file
|
||||
fs.writeFileSync(`${PW_BUILD_DATA_DIR}/version.json`, JSON.stringify(version))
|
||||
})()
|
||||
} catch (ex) {
|
||||
console.error(ex)
|
||||
process.exit(FAIL_ON_ERROR ? 1 : 0)
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
# COMPONENTS
|
||||
|
||||
**This directory is not required, you can delete it if you don't want to use it.**
|
||||
|
||||
The components directory contains your Vue.js Components.
|
||||
|
||||
_Nuxt.js doesn't supercharge these components._
|
||||
|
||||
175
components/app/Contributors.vue
Normal file
@@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<div>
|
||||
<p class="info">
|
||||
{{ $t("donate_info1") }}
|
||||
</p>
|
||||
<p class="info">
|
||||
{{ $t("donate_info2") }}
|
||||
</p>
|
||||
<div class="px-2 row-wrapper">
|
||||
<span>
|
||||
<a
|
||||
v-tooltip.right="$t('recurring')"
|
||||
href="https://github.com/sponsors/hoppscotch"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<button class="icon">
|
||||
<i class="material-icons">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
class="material-icons"
|
||||
>
|
||||
<path
|
||||
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<span>GitHub Sponsors</span>
|
||||
</button>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="px-2 row-wrapper">
|
||||
<span>
|
||||
<a
|
||||
v-tooltip.right="$t('one_time_recurring')"
|
||||
href="https://opencollective.com/hoppscotch"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<button class="icon">
|
||||
<i class="material-icons">donut_large</i>
|
||||
<span>{{ $t("open_collective") }}</span>
|
||||
</button>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="px-2 row-wrapper">
|
||||
<span>
|
||||
<a
|
||||
v-tooltip.right="$t('recurring')"
|
||||
href="https://www.patreon.com/liyasthomas"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<button class="icon">
|
||||
<i class="material-icons">local_parking</i>
|
||||
<span>{{ $t("patreon") }}</span>
|
||||
</button>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="px-2 row-wrapper">
|
||||
<span>
|
||||
<a
|
||||
v-tooltip.right="$t('one_time')"
|
||||
href="https://www.paypal.me/liyascthomas"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<button class="icon">
|
||||
<i class="material-icons">payment</i>
|
||||
<span>{{ $t("paypal") }}</span>
|
||||
</button>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="p-2">
|
||||
<h3 class="title">Financial Contributors</h3>
|
||||
<div class="contributors">
|
||||
<a
|
||||
href="https://oss.capital/?ref=hoppscotch"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<img
|
||||
style="height: 100%; width: 300px"
|
||||
src="~assets/images/ossc-banner.svg"
|
||||
alt="OSS Capital"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://appwrite.io/?utm_source=hoppscotch&utm_medium=banner&utm_campaign=hello"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<img
|
||||
style="height: 100%; width: 300px; background: #fff"
|
||||
src="~assets/images/appwrite-banner.svg"
|
||||
alt="Appwrite"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://pipedream.com/?ref=hoppscotch"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<img
|
||||
style="max-width: 100px"
|
||||
src="~assets/images/pipedream.png"
|
||||
alt="pipedream"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://paw.cloud/?utm_source=hoppscotch&utm_medium=website&utm_campaign=hoppscotch-sponsorship"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<img
|
||||
style="max-width: 100px"
|
||||
src="~assets/images/Paw-Logo-for-Hoppscotch.png"
|
||||
alt="Paw"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://simplescraper.io/?utm_source=hs"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<img
|
||||
style="max-height: 50px"
|
||||
src="~assets/images/Simplescraper_dark.png"
|
||||
alt="Simplescraper"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://tyk.io?ref=hoppscotch" target="_blank" rel="noopener">
|
||||
<img
|
||||
style="max-width: 320px"
|
||||
src="~assets/images/Tyk-side-project-logo-tagline-blk.png"
|
||||
alt="Tyk Banner"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<p class="info">
|
||||
This project exists thanks to all the
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
href="https://github.com/hoppscotch/hoppscotch/graphs/contributors"
|
||||
class="link"
|
||||
>
|
||||
people who contribute
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.contributors {
|
||||
@apply flex;
|
||||
@apply items-center;
|
||||
@apply flex-wrap;
|
||||
@apply overflow-auto;
|
||||
@apply m-2;
|
||||
@apply space-x-2;
|
||||
@apply space-y-2;
|
||||
}
|
||||
</style>
|
||||
106
components/app/Extensions.vue
Normal file
@@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("extensions") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<p class="info">
|
||||
{{ $t("extensions_info1") }}
|
||||
</p>
|
||||
<div class="px-2">
|
||||
<a
|
||||
href="https://addons.mozilla.org/en-US/firefox/addon/hoppscotch"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<button class="icon">
|
||||
<svg
|
||||
class="material-icons"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path
|
||||
d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm8.003 8.657c-1.276-3.321-4.46-4.605-5.534-4.537 3.529 1.376 4.373 6.059 4.06 7.441-.307-1.621-1.286-3.017-1.872-3.385 3.417 8.005-4.835 10.465-7.353 7.687.649.168 1.931.085 2.891-.557.898-.602.983-.638 1.56-.683.686-.053-.041-1.406-1.539-1.177-.616.094-1.632.819-2.88.341-1.508-.576-1.46-2.634.096-2.015.337-.437.088-1.263.088-1.263.452-.414 1.022-.706 1.37-.911.228-.135.829-.507.795-1.23-.123-.096-.32-.219-.766-.193-1.736.11-1.852-.518-1.967-.808.078-.668.524-1.534 1.361-1.931-1.257-.193-2.28.397-2.789 1.154-.809-.174-1.305-.183-2.118-.031-.316-.24-.666-.67-.878-1.181C6.36 3.312 9.027 2 12 2c5.912 0 8.263 4.283 8.003 6.657z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Firefox</span>
|
||||
<span
|
||||
v-if="hasFirefoxExtInstalled"
|
||||
v-tooltip="$t('installed')"
|
||||
class="icon"
|
||||
>
|
||||
<i class="material-icons">done</i>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
<div class="px-2">
|
||||
<a
|
||||
href="https://chrome.google.com/webstore/detail/hoppscotch-browser-extens/amknoiejhlmhancpahfcfcfhllgkpbld"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<button class="icon">
|
||||
<svg
|
||||
class="material-icons"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path
|
||||
d="M2.897 4.181A11.87 11.87 0 0111.969 0c4.288 0 8.535 2.273 10.717 6.554h-9.293c-1.674.001-2.755-.037-3.926.579-1.376.724-2.415 2.067-2.777 3.644L2.897 4.181zM8.007 12c0 2.2 1.789 3.99 3.988 3.99s3.988-1.79 3.988-3.99-1.789-3.991-3.988-3.991S8.007 9.8 8.007 12zm5.536 5.223c-2.238.666-4.858-.073-6.293-2.549-1.095-1.891-3.989-6.933-5.305-9.225A11.856 11.856 0 000 11.956c0 5.448 3.726 10.65 9.673 11.818l3.87-6.551zm2.158-9.214a5.463 5.463 0 011.007 6.719 1815.43 1815.43 0 01-5.46 9.248C18.437 24.419 24 18.616 24 12.004c0-1.313-.22-2.66-.69-3.995h-7.609z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Chrome</span>
|
||||
<span
|
||||
v-if="hasChromeExtInstalled"
|
||||
v-tooltip="$t('installed')"
|
||||
class="icon"
|
||||
>
|
||||
<i class="material-icons">done</i>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer"></div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
hasChromeExtensionInstalled,
|
||||
hasFirefoxExtensionInstalled,
|
||||
} from "~/helpers/strategies/ExtensionStrategy"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasChromeExtInstalled: hasChromeExtensionInstalled(),
|
||||
hasFirefoxExtInstalled: hasFirefoxExtensionInstalled(),
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show() {
|
||||
this.hasChromeExtInstalled = hasChromeExtensionInstalled()
|
||||
this.hasFirefoxExtInstalled = hasFirefoxExtensionInstalled()
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
104
components/app/Footer.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<footer class="footer">
|
||||
<div class="row-wrapper">
|
||||
<span
|
||||
class="flex flex-col font-mono md:flex-row"
|
||||
style="align-items: start"
|
||||
>
|
||||
<a
|
||||
class="footer-link"
|
||||
href="https://www.netlify.com"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
Powered by Netlify
|
||||
</a>
|
||||
<span>
|
||||
<a
|
||||
class="footer-link"
|
||||
href="https://oss.capital/?ref=hoppscotch"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
OSS Capital
|
||||
</a>
|
||||
<a
|
||||
class="footer-link"
|
||||
href="https://paw.cloud/?utm_source=hoppscotch&utm_medium=website&utm_campaign=hoppscotch-sponsorship"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
Paw
|
||||
</a>
|
||||
<a
|
||||
class="footer-link"
|
||||
href="https://simplescraper.io/?utm_source=hs"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
Simplescraper
|
||||
</a>
|
||||
</span>
|
||||
<iframe
|
||||
src="https://ghbtns.com/github-btn.html?user=hoppscotch&type=sponsor"
|
||||
frameborder="0"
|
||||
scrolling="0"
|
||||
width="150"
|
||||
height="20"
|
||||
title="GitHub"
|
||||
class="footer-link"
|
||||
loading="lazy"
|
||||
></iframe>
|
||||
</span>
|
||||
<span
|
||||
class="flex flex-col font-mono md:flex-row"
|
||||
style="align-items: start"
|
||||
>
|
||||
<a href="mailto:support@hoppscotch.io" target="_blank" rel="noopener">
|
||||
<button v-tooltip="$t('contact_us')" class="icon">
|
||||
<i class="material-icons">email</i>
|
||||
</button>
|
||||
</a>
|
||||
<v-popover>
|
||||
<button v-tooltip="$t('choose_language')" class="icon">
|
||||
<i class="material-icons">translate</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div v-for="locale in availableLocales" :key="locale.code">
|
||||
<nuxt-link :to="switchLocalePath(locale.code)">
|
||||
<button v-close-popover class="icon">
|
||||
{{ locale.name }}
|
||||
</button>
|
||||
</nuxt-link>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</span>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
computed: {
|
||||
availableLocales() {
|
||||
return this.$i18n.locales.filter(({ code }) => code !== this.$i18n.locale)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.footer-link {
|
||||
@apply inline-flex;
|
||||
@apply flex-shrink-0;
|
||||
@apply my-2;
|
||||
@apply mx-4;
|
||||
@apply text-fgLightColor;
|
||||
@apply text-sm;
|
||||
|
||||
&:hover {
|
||||
@apply text-fgColor;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
342
components/app/Header.vue
Normal file
@@ -0,0 +1,342 @@
|
||||
<template>
|
||||
<header class="header">
|
||||
<div class="row-wrapper">
|
||||
<span class="slide-in">
|
||||
<nuxt-link :to="localePath('index')">
|
||||
<h1 class="hide-on-small-screen logo">Hoppscotch</h1>
|
||||
<h1 class="show-on-small-screen logo">Hs</h1>
|
||||
</nuxt-link>
|
||||
<iframe
|
||||
src="https://ghbtns.com/github-btn.html?user=hoppscotch&repo=hoppscotch&type=star&count=true"
|
||||
frameborder="0"
|
||||
scrolling="0"
|
||||
width="150"
|
||||
height="20"
|
||||
title="GitHub"
|
||||
class="ml-8 hide-on-small-screen"
|
||||
loading="lazy"
|
||||
></iframe>
|
||||
</span>
|
||||
<span>
|
||||
<a
|
||||
href="https://appwrite.io/?utm_source=hoppscotch&utm_medium=banner&utm_campaign=hello"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
class="
|
||||
inline-flex
|
||||
items-center
|
||||
px-4
|
||||
py-2
|
||||
mx-4
|
||||
font-mono
|
||||
text-sm
|
||||
rounded-md
|
||||
bg-bgDarkColor
|
||||
hide-on-small-screen
|
||||
"
|
||||
>
|
||||
Appwrite - Open-Source Backend as a Service
|
||||
<img
|
||||
class="w-8 ml-2"
|
||||
src="~assets/images/appwrite-icon.svg"
|
||||
alt="Appwrite"
|
||||
/>
|
||||
</a>
|
||||
<button
|
||||
id="installPWA"
|
||||
v-tooltip="$t('install_pwa')"
|
||||
class="icon"
|
||||
@click.prevent="showInstallPrompt()"
|
||||
>
|
||||
<i class="material-icons">offline_bolt</i>
|
||||
</button>
|
||||
<a
|
||||
href="https://github.com/hoppscotch/hoppscotch"
|
||||
target="_blank"
|
||||
aria-label="GitHub"
|
||||
rel="noopener"
|
||||
>
|
||||
<button v-tooltip="'GitHub'" class="icon" aria-label="GitHub">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
class="material-icons"
|
||||
>
|
||||
<path
|
||||
d="M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</a>
|
||||
<v-popover v-if="fb.currentUser === null">
|
||||
<button v-tooltip="$t('login_with')" class="icon">
|
||||
<i class="material-icons">login</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<FirebaseLogin />
|
||||
</template>
|
||||
</v-popover>
|
||||
<v-popover v-else>
|
||||
<button
|
||||
v-tooltip="
|
||||
(fb.currentUser.displayName ||
|
||||
'<label><i>Name not found</i></label>') +
|
||||
'<br>' +
|
||||
(fb.currentUser.email || '<label><i>Email not found</i></label>')
|
||||
"
|
||||
class="icon"
|
||||
aria-label="Account"
|
||||
>
|
||||
<img
|
||||
v-if="fb.currentUser.photoURL"
|
||||
:src="fb.currentUser.photoURL"
|
||||
class="w-6 h-6 rounded-full material-icons"
|
||||
alt="Profile image"
|
||||
/>
|
||||
<i v-else class="material-icons">account_circle</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<nuxt-link v-close-popover :to="localePath('settings')">
|
||||
<button class="icon">
|
||||
<i class="material-icons">settings</i>
|
||||
<span>
|
||||
{{ $t("settings") }}
|
||||
</span>
|
||||
</button>
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<div>
|
||||
<FirebaseLogout />
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
<v-popover>
|
||||
<button v-tooltip="$t('more')" class="icon">
|
||||
<i class="material-icons">drag_indicator</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<button v-close-popover class="icon" @click="showExtensions = true">
|
||||
<i class="material-icons">extension</i>
|
||||
<span>{{ $t("extensions") }}</span>
|
||||
</button>
|
||||
<button v-close-popover class="icon" @click="showShortcuts = true">
|
||||
<i class="material-icons">keyboard</i>
|
||||
<span>{{ $t("shortcuts") }}</span>
|
||||
</button>
|
||||
<button v-close-popover class="icon" @click="showSupport = true">
|
||||
<i class="material-icons">favorite</i>
|
||||
<span>{{ $t("support_us") }}</span>
|
||||
</button>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
onClick="window.open('https://twitter.com/share?text=👽 Hoppscotch • Open source API development ecosystem - Helps you create requests faster, saving precious time on development.&url=https://hoppscotch.io&hashtags=hoppscotch&via=hoppscotch_io');"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
|
||||
<path
|
||||
d="M24 4.557a9.83 9.83 0 01-2.828.775 4.932 4.932 0 002.165-2.724 9.864 9.864 0 01-3.127 1.195 4.916 4.916 0 00-3.594-1.555c-3.179 0-5.515 2.966-4.797 6.045A13.978 13.978 0 011.671 3.149a4.93 4.93 0 001.523 6.574 4.903 4.903 0 01-2.229-.616c-.054 2.281 1.581 4.415 3.949 4.89a4.935 4.935 0 01-2.224.084 4.928 4.928 0 004.6 3.419A9.9 9.9 0 010 19.54a13.94 13.94 0 007.548 2.212c9.142 0 14.307-7.721 13.995-14.646A10.025 10.025 0 0024 4.557z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Tweet</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="navigatorShare"
|
||||
v-close-popover
|
||||
v-tooltip="$t('more')"
|
||||
class="icon"
|
||||
@click="nativeShare"
|
||||
>
|
||||
<i class="material-icons">share</i>
|
||||
<span>Share</span>
|
||||
</button>
|
||||
</template>
|
||||
</v-popover>
|
||||
</span>
|
||||
</div>
|
||||
<AppExtensions
|
||||
:show="showExtensions"
|
||||
@hide-modal="showExtensions = false"
|
||||
/>
|
||||
<AppShortcuts :show="showShortcuts" @hide-modal="showShortcuts = false" />
|
||||
<AppSupport :show="showSupport" @hide-modal="showSupport = false" />
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import intializePwa from "~/helpers/pwa"
|
||||
import { fb } from "~/helpers/fb"
|
||||
// import { hasExtensionInstalled } from "~/helpers/strategies/ExtensionStrategy"
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// Once the PWA code is initialized, this holds a method
|
||||
// that can be called to show the user the installation
|
||||
// prompt.
|
||||
showInstallPrompt: null,
|
||||
showExtensions: false,
|
||||
showShortcuts: false,
|
||||
showSupport: false,
|
||||
navigatorShare: navigator.share,
|
||||
fb,
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
this._keyListener = function (e) {
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault()
|
||||
this.showExtensions = this.showShortcuts = this.showSupport = false
|
||||
}
|
||||
}
|
||||
document.addEventListener("keydown", this._keyListener.bind(this))
|
||||
|
||||
// Initializes the PWA code - checks if the app is installed,
|
||||
// etc.
|
||||
this.showInstallPrompt = await intializePwa()
|
||||
const cookiesAllowed = localStorage.getItem("cookiesAllowed") === "yes"
|
||||
if (!cookiesAllowed) {
|
||||
this.$toast.show(this.$t("we_use_cookies"), {
|
||||
icon: "info",
|
||||
duration: 5000,
|
||||
theme: "toasted-primary",
|
||||
action: [
|
||||
{
|
||||
text: this.$t("dismiss"),
|
||||
onClick: (_, toastObject) => {
|
||||
localStorage.setItem("cookiesAllowed", "yes")
|
||||
toastObject.goAway(0)
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
// let showAd = localStorage.getItem("showAd") === "no"
|
||||
// if (!showAd) {
|
||||
// setTimeout(() => {
|
||||
// this.$toast.clear()
|
||||
// this.$toast.show(
|
||||
// "<span><a href='https://github.com/sponsors/hoppscotch' target='_blank' rel='noopener'>Sponsor us to support Hoppscotch open source project 💖</a><br><sub>Whoosh this away to dismiss.</sub></span>",
|
||||
// {
|
||||
// icon: "",
|
||||
// duration: 0,
|
||||
// theme: "toasted-ad",
|
||||
// action: [
|
||||
// {
|
||||
// text: "Sponsor",
|
||||
// icon: "chevron_right",
|
||||
// onClick: (_, toastObject) => {
|
||||
// localStorage.setItem("showAd", "no")
|
||||
// toastObject.goAway(0)
|
||||
// window.open("https://github.com/sponsors/hoppscotch")
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// onComplete() {
|
||||
// localStorage.setItem("showAd", "no")
|
||||
// },
|
||||
// }
|
||||
// )
|
||||
// }, 8000)
|
||||
// }
|
||||
|
||||
// let showExtensionsToast = localStorage.getItem("showExtensionsToast") === "yes"
|
||||
// if (!showExtensionsToast) {
|
||||
// setTimeout(() => {
|
||||
// if (!hasExtensionInstalled()) {
|
||||
// this.$toast.show(this.$t("extensions_info2"), {
|
||||
// icon: "extension",
|
||||
// duration: 5000,
|
||||
// theme: "toasted-primary",
|
||||
// action: [
|
||||
// {
|
||||
// text: this.$t("yes"),
|
||||
// onClick: (_, toastObject) => {
|
||||
// this.showExtensions = true
|
||||
// localStorage.setItem("showExtensionsToast", "yes")
|
||||
// toastObject.goAway(0)
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// text: this.$t("no"),
|
||||
// onClick: (_, toastObject) => {
|
||||
// this.$store.commit("setMiscState", {
|
||||
// value: false,
|
||||
// attribute: "showExtensionsToast",
|
||||
// })
|
||||
// localStorage.setItem("showExtensionsToast", "no")
|
||||
// toastObject.goAway(0)
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// })
|
||||
// }
|
||||
// }, 5000)
|
||||
// }
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("keydown", this._keyListener)
|
||||
},
|
||||
methods: {
|
||||
nativeShare() {
|
||||
if (navigator.share) {
|
||||
navigator
|
||||
.share({
|
||||
title: "Hoppscotch",
|
||||
text: "Hoppscotch • Open source API development ecosystem - Helps you create requests faster, saving precious time on development.",
|
||||
url: "https://hoppscotch.io",
|
||||
})
|
||||
.then(() => {})
|
||||
.catch(console.error)
|
||||
} else {
|
||||
// fallback
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$responsiveWidth: 768px;
|
||||
|
||||
.logo {
|
||||
@apply text-xl;
|
||||
@apply transition-colors;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
|
||||
&:hover {
|
||||
@apply text-acColor;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
0% {
|
||||
@apply opacity-0;
|
||||
@apply -left-4;
|
||||
}
|
||||
|
||||
100% {
|
||||
@apply opacity-100;
|
||||
@apply left-0;
|
||||
}
|
||||
}
|
||||
|
||||
.slide-in {
|
||||
@apply relative;
|
||||
|
||||
animation: slideIn 0.2s forwards ease-in-out;
|
||||
}
|
||||
|
||||
.show-on-small-screen {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
@media (max-width: $responsiveWidth) {
|
||||
.show-on-small-screen {
|
||||
@apply inline-flex;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -15,6 +15,7 @@ export default {
|
||||
props: {
|
||||
color: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
74
components/app/Section.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<fieldset :id="label.toLowerCase()">
|
||||
<legend v-if="!noLegend" @click.prevent="collapse">
|
||||
<span>{{ label }}</span>
|
||||
<i class="ml-2 align-middle material-icons">
|
||||
{{ isCollapsed(label) ? "expand_more" : "expand_less" }}
|
||||
</i>
|
||||
</legend>
|
||||
<div
|
||||
class="collapsible"
|
||||
:class="{ hidden: isCollapsed(label.toLowerCase()) }"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</fieldset>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue"
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
label: {
|
||||
type: String,
|
||||
default: "Section",
|
||||
},
|
||||
noLegend: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
sectionString(): string {
|
||||
return `${this.$route.path.replace(/\/+$/, "")}/${this.label}`
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
collapse() {
|
||||
// Save collapsed section into the collapsedSections array
|
||||
this.$store.commit("setCollapsedSection", this.sectionString)
|
||||
},
|
||||
isCollapsed(_label: string) {
|
||||
return (
|
||||
this.$store.state.theme.collapsedSections.includes(
|
||||
this.sectionString
|
||||
) || false
|
||||
)
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
fieldset {
|
||||
@apply my-4;
|
||||
@apply rounded-lg;
|
||||
@apply bg-bgDarkColor;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
@apply w-full;
|
||||
|
||||
legend {
|
||||
@apply px-4;
|
||||
@apply text-fgColor;
|
||||
@apply font-bold;
|
||||
@apply cursor-pointer;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
102
components/app/Shortcuts.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("shortcuts") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<div class="p-2">
|
||||
<div>
|
||||
<kbd>{{ getSpecialKey() }}</kbd>
|
||||
+
|
||||
<kbd>G</kbd>
|
||||
<label>{{ $t("send_request") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>{{ getSpecialKey() }}</kbd
|
||||
>+<kbd>S</kbd>
|
||||
<label>{{ $t("save_to_collections") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>{{ getSpecialKey() }}</kbd
|
||||
>+<kbd>K</kbd>
|
||||
<label>{{ $t("copy_request_link") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>{{ getSpecialKey() }}</kbd
|
||||
>+<kbd>I</kbd>
|
||||
<label>{{ $t("reset_request") }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="p-2">
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>▲</kbd>
|
||||
<label>{{ $t("select_next_method") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>▼</kbd>
|
||||
<label>{{ $t("select_previous_method") }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="p-2">
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>G</kbd>
|
||||
<label>{{ $t("select_get_method") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>H</kbd>
|
||||
<label>{{ $t("select_head_method") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>P</kbd>
|
||||
<label>{{ $t("select_post_method") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>U</kbd>
|
||||
<label>{{ $t("select_put_method") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>X</kbd>
|
||||
<label>{{ $t("select_delete_method") }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer"></div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getPlatformSpecialKey } from "~/helpers/platformutils"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
methods: {
|
||||
getSpecialKey: getPlatformSpecialKey,
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
kbd {
|
||||
@apply inline-flex;
|
||||
@apply resize-none;
|
||||
@apply m-2;
|
||||
@apply rounded-lg;
|
||||
@apply py-2;
|
||||
@apply px-4;
|
||||
@apply text-sm;
|
||||
}
|
||||
</style>
|
||||
307
components/app/Sidenav.vue
Normal file
@@ -0,0 +1,307 @@
|
||||
<template>
|
||||
<aside class="nav-first">
|
||||
<nav class="primary-nav">
|
||||
<!--
|
||||
We're using manual checks for linkActive because the query string
|
||||
seems to mess up the nuxt-link active class.
|
||||
-->
|
||||
<nuxt-link
|
||||
v-tooltip.right="$t('home')"
|
||||
:to="localePath('index')"
|
||||
:class="linkActive('/')"
|
||||
:aria-label="$t('home')"
|
||||
>
|
||||
<AppLogo alt class="material-icons" style="height: 24px" />
|
||||
</nuxt-link>
|
||||
<nuxt-link
|
||||
v-tooltip.right="$t('realtime')"
|
||||
:to="localePath('realtime')"
|
||||
:class="linkActive('/realtime')"
|
||||
>
|
||||
<i class="material-icons">language</i>
|
||||
</nuxt-link>
|
||||
<nuxt-link
|
||||
v-tooltip.right="$t('graphql')"
|
||||
:to="localePath('graphql')"
|
||||
:class="linkActive('/graphql')"
|
||||
:aria-label="$t('graphql')"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24"
|
||||
width="24"
|
||||
viewBox="0 0 29.999 30"
|
||||
>
|
||||
<path d="M4.08 22.864l-1.1-.636L15.248.98l1.1.636z" />
|
||||
<path d="M2.727 20.53h24.538v1.272H2.727z" />
|
||||
<path
|
||||
d="M15.486 28.332L3.213 21.246l.636-1.1 12.273 7.086zm10.662-18.47L13.874 2.777l.636-1.1 12.273 7.086z"
|
||||
/>
|
||||
<path d="M3.852 9.858l-.636-1.1L15.5 1.67l.636 1.1z" />
|
||||
<path
|
||||
d="M25.922 22.864l-12.27-21.25 1.1-.636 12.27 21.25zM3.7 7.914h1.272v14.172H3.7zm21.328 0H26.3v14.172h-1.272z"
|
||||
/>
|
||||
<path d="M15.27 27.793l-.555-.962 10.675-6.163.555.962z" />
|
||||
<path
|
||||
d="M27.985 22.5a2.68 2.68 0 01-3.654.981 2.68 2.68 0 01-.981-3.654 2.68 2.68 0 013.654-.981 2.665 2.665 0 01.98 3.654M6.642 10.174a2.68 2.68 0 01-3.654.981A2.68 2.68 0 012.007 7.5a2.68 2.68 0 013.654-.981 2.68 2.68 0 01.981 3.654M2.015 22.5a2.68 2.68 0 01.981-3.654 2.68 2.68 0 013.654.981 2.68 2.68 0 01-.981 3.654c-1.287.735-2.92.3-3.654-.98m21.343-12.326a2.68 2.68 0 01.981-3.654 2.68 2.68 0 013.654.981 2.68 2.68 0 01-.981 3.654 2.68 2.68 0 01-3.654-.981M15 30a2.674 2.674 0 112.674-2.673A2.68 2.68 0 0115 30m0-24.652a2.67 2.67 0 01-2.674-2.674 2.67 2.67 0 115.347 0A2.67 2.67 0 0115 5.347"
|
||||
/>
|
||||
</svg>
|
||||
</nuxt-link>
|
||||
<nuxt-link
|
||||
v-tooltip.right="$t('documentation')"
|
||||
:to="localePath('doc')"
|
||||
:class="linkActive('/doc')"
|
||||
:aria-label="$t('documentation')"
|
||||
>
|
||||
<i class="material-icons">topic</i>
|
||||
</nuxt-link>
|
||||
<nuxt-link
|
||||
v-tooltip.right="$t('settings')"
|
||||
:to="localePath('settings')"
|
||||
:class="linkActive('/settings')"
|
||||
:aria-label="$t('settings')"
|
||||
>
|
||||
<i class="material-icons">settings</i>
|
||||
</nuxt-link>
|
||||
</nav>
|
||||
<nav v-if="$route.path == '/'" class="secondary-nav">
|
||||
<a v-tooltip.right="$t('request')" href="#request">
|
||||
<i class="material-icons">cloud_upload</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('options')" href="#options">
|
||||
<i class="material-icons">toc</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('response')" href="#response">
|
||||
<i class="material-icons">cloud_download</i>
|
||||
</a>
|
||||
</nav>
|
||||
<nav v-else-if="$route.path.includes('/realtime')" class="secondary-nav">
|
||||
<a v-tooltip.right="$t('request')" href="#request">
|
||||
<i class="material-icons">cloud_upload</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('communication')" href="#response">
|
||||
<i class="material-icons">cloud_download</i>
|
||||
</a>
|
||||
</nav>
|
||||
<nav v-else-if="$route.path.includes('/graphql')" class="secondary-nav">
|
||||
<a v-tooltip.right="$t('endpoint')" href="#endpoint">
|
||||
<i class="material-icons">cloud</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('schema')" href="#schema">
|
||||
<i class="material-icons">assignment_returned</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('query')" href="#query">
|
||||
<i class="material-icons">cloud_upload</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('response')" href="#response">
|
||||
<i class="material-icons">cloud_download</i>
|
||||
</a>
|
||||
</nav>
|
||||
<nav v-else-if="$route.path.includes('/doc')" class="secondary-nav">
|
||||
<a v-tooltip.right="$t('import')" href="#import">
|
||||
<i class="material-icons">folder</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('documentation')" href="#documentation">
|
||||
<i class="material-icons">insert_drive_file</i>
|
||||
</a>
|
||||
</nav>
|
||||
<nav v-else-if="$route.path.includes('/settings')" class="secondary-nav">
|
||||
<a v-tooltip.right="$t('account')" href="#account">
|
||||
<i class="material-icons">person</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('theme')" href="#theme">
|
||||
<i class="material-icons">brush</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('extensions')" href="#extensions">
|
||||
<i class="material-icons">extension</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('proxy')" href="#proxy">
|
||||
<i class="material-icons">public</i>
|
||||
</a>
|
||||
</nav>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
mounted() {
|
||||
window.addEventListener("scroll", () => {
|
||||
const mainNavLinks = document.querySelectorAll("nav.secondary-nav a")
|
||||
const fromTop = window.scrollY
|
||||
mainNavLinks.forEach(({ hash, classList }) => {
|
||||
const section = document.querySelector(hash)
|
||||
if (
|
||||
section &&
|
||||
section.offsetTop <= fromTop &&
|
||||
section.offsetTop + section.offsetHeight > fromTop
|
||||
) {
|
||||
classList.add("current")
|
||||
} else {
|
||||
classList.remove("current")
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
linkActive(path) {
|
||||
return {
|
||||
"nuxt-link-exact-active": this.$route.path === path,
|
||||
"nuxt-link-active": this.$route.path === path,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$responsiveWidth: 768px;
|
||||
|
||||
.nav-first {
|
||||
@apply z-10;
|
||||
@apply h-screen;
|
||||
@apply p-2;
|
||||
@apply bg-bgDarkColor;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
@apply space-y-2;
|
||||
}
|
||||
|
||||
nav.primary-nav {
|
||||
@apply flex;
|
||||
@apply flex-col;
|
||||
@apply flex-nowrap;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply space-y-2;
|
||||
@apply w-full;
|
||||
|
||||
svg {
|
||||
@apply fill-current;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply inline-flex;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply flex-shrink-0;
|
||||
@apply p-4;
|
||||
@apply rounded-full;
|
||||
@apply bg-bgLightColor;
|
||||
@apply text-fgLightColor;
|
||||
@apply fill-current;
|
||||
@apply outline-none;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
|
||||
&:hover {
|
||||
@apply text-fgColor;
|
||||
@apply fill-current;
|
||||
|
||||
svg {
|
||||
@apply fill-current;
|
||||
}
|
||||
}
|
||||
|
||||
&.nuxt-link-exact-active {
|
||||
@apply bg-acColor;
|
||||
@apply text-actColor;
|
||||
@apply fill-current;
|
||||
|
||||
border-radius: 16px;
|
||||
|
||||
svg {
|
||||
@apply fill-current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nav.primary-nav::-webkit-scrollbar,
|
||||
.nav-first::-webkit-scrollbar {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
nav.secondary-nav {
|
||||
@apply flex;
|
||||
@apply flex-col;
|
||||
@apply flex-nowrap;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply border-t-2;
|
||||
@apply border-dashed;
|
||||
@apply border-brdColor;
|
||||
@apply pt-2;
|
||||
@apply space-y-2;
|
||||
|
||||
a {
|
||||
@apply inline-flex;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply flex-shrink-0;
|
||||
@apply p-4;
|
||||
@apply rounded-full;
|
||||
@apply bg-bgDarkColor;
|
||||
@apply text-fgLightColor;
|
||||
@apply fill-current;
|
||||
@apply outline-none;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
|
||||
&:hover {
|
||||
@apply text-fgColor;
|
||||
@apply fill-current;
|
||||
}
|
||||
|
||||
&.current {
|
||||
@apply text-acColor;
|
||||
@apply fill-current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $responsiveWidth) {
|
||||
.nav-first {
|
||||
@apply fixed;
|
||||
@apply top-auto;
|
||||
@apply bottom-0;
|
||||
@apply h-auto;
|
||||
@apply p-0;
|
||||
@apply w-full;
|
||||
@apply bg-bgColor;
|
||||
@apply shadow-2xl;
|
||||
}
|
||||
|
||||
nav.primary-nav {
|
||||
@apply flex-row;
|
||||
@apply flex-nowrap;
|
||||
@apply overflow-auto;
|
||||
@apply bg-bgDarkColor;
|
||||
@apply space-y-0;
|
||||
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
a {
|
||||
@apply bg-transparent;
|
||||
@apply my-2;
|
||||
@apply flex-1;
|
||||
|
||||
&.nuxt-link-exact-active {
|
||||
@apply bg-transparent;
|
||||
@apply text-acColor;
|
||||
@apply fill-current;
|
||||
|
||||
svg {
|
||||
@apply fill-current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nav.secondary-nav {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
31
components/app/Support.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("support_us") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<AppContributors />
|
||||
</div>
|
||||
<div slot="footer"></div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
methods: {
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
60
components/collections/Add.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("new_collection") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="$t('my_new_collection')"
|
||||
@keyup.enter="addNewCollection"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="addNewCollection">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addNewCollection() {
|
||||
this.$emit("submit", this.name)
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
67
components/collections/AddFolder.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="$emit('hide-modal')">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("new_folder") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="$t('my_new_folder')"
|
||||
@keyup.enter="addFolder"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="addFolder">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
folder: { type: Object, default: () => {} },
|
||||
folderPath: { type: String, default: null },
|
||||
collectionIndex: { type: Number, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addFolder() {
|
||||
this.$emit("add-folder", {
|
||||
name: this.name,
|
||||
folder: this.folder,
|
||||
path: this.folderPath || `${this.collectionIndex}`,
|
||||
})
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
105
components/collections/ChooseType.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div v-if="show">
|
||||
<SmartTabs
|
||||
:id="'collections_tab'"
|
||||
styles="m-4"
|
||||
@tab-changed="updateCollectionsType"
|
||||
>
|
||||
<SmartTab
|
||||
:id="'my-collections'"
|
||||
:label="'My Collections'"
|
||||
:selected="true"
|
||||
/>
|
||||
<SmartTab
|
||||
v-if="currentUser && currentUser.eaInvited && !doc"
|
||||
:id="'team-collections'"
|
||||
:label="'Team Collections'"
|
||||
>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="select-wrapper">
|
||||
<SmartIntersection @intersecting="onTeamSelectIntersect">
|
||||
<select
|
||||
id="team"
|
||||
type="text"
|
||||
class="team"
|
||||
autofocus
|
||||
@change="updateSelectedTeam(myTeams[$event.target.value])"
|
||||
>
|
||||
<option
|
||||
:key="undefined"
|
||||
:value="undefined"
|
||||
hidden
|
||||
disabled
|
||||
selected
|
||||
>
|
||||
Select team
|
||||
</option>
|
||||
<option
|
||||
v-for="(team, index) in myTeams"
|
||||
:key="index"
|
||||
:value="index"
|
||||
>
|
||||
{{ team.name }}
|
||||
</option>
|
||||
</select>
|
||||
</SmartIntersection>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</SmartTab>
|
||||
</SmartTabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from "graphql-tag"
|
||||
import { currentUserInfo$ } from "~/helpers/teams/BackendUserInfo"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
doc: Boolean,
|
||||
show: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
skipTeamsFetching: true,
|
||||
}
|
||||
},
|
||||
subscriptions() {
|
||||
return {
|
||||
currentUser: currentUserInfo$,
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
myTeams: {
|
||||
query: gql`
|
||||
query GetMyTeams {
|
||||
myTeams {
|
||||
id
|
||||
name
|
||||
myRole
|
||||
}
|
||||
}
|
||||
`,
|
||||
pollInterval: 10000,
|
||||
skip() {
|
||||
return this.skipTeamsFetching
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onTeamSelectIntersect() {
|
||||
// Load team data as soon as intersection
|
||||
this.$apollo.queries.myTeams.refetch()
|
||||
this.skipTeamsFetching = false
|
||||
},
|
||||
updateCollectionsType(tabID) {
|
||||
this.$emit("update-collection-type", tabID)
|
||||
},
|
||||
updateSelectedTeam(team) {
|
||||
this.$emit("update-selected-team", team)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
61
components/collections/Edit.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_collection") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="placeholderCollName"
|
||||
@keyup.enter="saveCollection"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="saveCollection">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
placeholderCollName: { type: String, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
saveCollection() {
|
||||
this.$emit("submit", this.name)
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
59
components/collections/EditFolder.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="$emit('hide-modal')">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_folder") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
@keyup.enter="editFolder"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="editFolder">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editFolder() {
|
||||
this.$emit("submit", this.name)
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
63
components/collections/EditRequest.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_request") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="requestUpdateData.name"
|
||||
type="text"
|
||||
:placeholder="placeholderReqName"
|
||||
@keyup.enter="saveRequest"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="saveRequest">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
placeholderReqName: { type: String, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
requestUpdateData: {
|
||||
name: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
saveRequest() {
|
||||
this.$emit("submit", this.requestUpdateData)
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.requestUpdateData = { name: null }
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
610
components/collections/ImportExport.vue
Normal file
@@ -0,0 +1,610 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">Export</h3>
|
||||
<div>
|
||||
<button
|
||||
v-if="mode != 'import_export'"
|
||||
v-tooltip.left="'Back'"
|
||||
class="tooltip-target icon"
|
||||
@click="mode = 'import_export'"
|
||||
>
|
||||
<i class="material-icons">arrow_back</i>
|
||||
</button>
|
||||
<v-popover
|
||||
v-if="
|
||||
mode == 'import_export' &&
|
||||
collectionsType.type == 'my-collections'
|
||||
"
|
||||
>
|
||||
<button v-tooltip.left="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="readCollectionGist"
|
||||
>
|
||||
<i class="material-icons">assignment_returned</i>
|
||||
<span>{{ $t("import_from_gist") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-tooltip.bottom="{
|
||||
content: !fb.currentUser
|
||||
? $t('login_with_github_to') + $t('create_secret_gist')
|
||||
: fb.currentUser.provider !== 'github.com'
|
||||
? $t('login_with_github_to') + $t('create_secret_gist')
|
||||
: null,
|
||||
}"
|
||||
>
|
||||
<button
|
||||
v-close-popover
|
||||
:disabled="
|
||||
!fb.currentUser
|
||||
? true
|
||||
: fb.currentUser.provider !== 'github.com'
|
||||
? true
|
||||
: false
|
||||
"
|
||||
class="icon"
|
||||
@click="createCollectionGist"
|
||||
>
|
||||
<i class="material-icons">assignment_turned_in</i>
|
||||
<span>{{ $t("create_secret_gist") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<div v-if="mode == 'import_export'" class="flex flex-col items-start p-2">
|
||||
<span
|
||||
v-tooltip="{
|
||||
content: !fb.currentUser
|
||||
? $t('login_first')
|
||||
: $t('replace_current'),
|
||||
}"
|
||||
>
|
||||
<button
|
||||
v-if="collectionsType.type == 'my-collections'"
|
||||
:disabled="!fb.currentUser"
|
||||
class="icon"
|
||||
@click="syncCollections"
|
||||
>
|
||||
<i class="material-icons">folder_shared</i>
|
||||
<span>{{ $t("import_from_sync") }}</span>
|
||||
</button>
|
||||
</span>
|
||||
<button
|
||||
v-tooltip="$t('replace_current')"
|
||||
class="icon"
|
||||
@click="openDialogChooseFileToReplaceWith"
|
||||
>
|
||||
<i class="material-icons">create_new_folder</i>
|
||||
<span>{{ $t("replace_json") }}</span>
|
||||
<input
|
||||
ref="inputChooseFileToReplaceWith"
|
||||
type="file"
|
||||
style="display: none"
|
||||
accept="application/json"
|
||||
@change="replaceWithJSON"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
v-tooltip="$t('preserve_current')"
|
||||
class="icon"
|
||||
@click="openDialogChooseFileToImportFrom"
|
||||
>
|
||||
<i class="material-icons">folder_special</i>
|
||||
<span>{{ $t("import_json") }}</span>
|
||||
<input
|
||||
ref="inputChooseFileToImportFrom"
|
||||
type="file"
|
||||
style="display: none"
|
||||
accept="application/json"
|
||||
@change="importFromJSON"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
v-if="collectionsType.type == 'team-collections'"
|
||||
v-tooltip="$t('replace_current')"
|
||||
class="icon"
|
||||
@click="mode = 'import_from_my_collections'"
|
||||
>
|
||||
<i class="material-icons">folder_special</i>
|
||||
<span>{{ "Import from My Collections" }}</span>
|
||||
</button>
|
||||
<button
|
||||
v-tooltip="$t('show_code')"
|
||||
class="icon"
|
||||
@click="
|
||||
() => {
|
||||
mode = 'export_as_json'
|
||||
getJSONCollection()
|
||||
}
|
||||
"
|
||||
>
|
||||
<i class="material-icons">folder_special</i>
|
||||
<span>{{ "Export As JSON" }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="mode == 'import_from_my_collections'">
|
||||
<span class="select-wrapper">
|
||||
<select
|
||||
type="text"
|
||||
autofocus
|
||||
@change="
|
||||
($event) => {
|
||||
mySelectedCollectionID = $event.target.value
|
||||
}
|
||||
"
|
||||
>
|
||||
<option
|
||||
:key="undefined"
|
||||
:value="undefined"
|
||||
hidden
|
||||
disabled
|
||||
selected
|
||||
>
|
||||
Select Collection
|
||||
</option>
|
||||
<option
|
||||
v-for="(collection, index) in myCollections"
|
||||
:key="index"
|
||||
:value="index"
|
||||
>
|
||||
{{ collection.name }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
<button
|
||||
class="m-2 icon primary"
|
||||
:disabled="mySelectedCollectionID == undefined"
|
||||
@click="importFromMyCollections"
|
||||
>
|
||||
{{ $t("import") }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="mode == 'export_as_json'">
|
||||
<textarea v-model="collectionJson" rows="8" readonly></textarea>
|
||||
<div class="row-wrapper">
|
||||
<span class="m-2">
|
||||
<button
|
||||
v-tooltip="$t('download_file')"
|
||||
class="icon primary"
|
||||
@click="exportJSON"
|
||||
>
|
||||
{{ $t("export") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
import { getSettingSubject } from "~/newstore/settings"
|
||||
import * as teamUtils from "~/helpers/teams/utils"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
collectionsType: { type: Object, default: () => {} },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fb,
|
||||
showJsonCode: false,
|
||||
mode: "import_export",
|
||||
mySelectedCollectionID: undefined,
|
||||
collectionJson: "",
|
||||
}
|
||||
},
|
||||
subscriptions() {
|
||||
return {
|
||||
SYNC_COLLECTIONS: getSettingSubject("syncCollections"),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
myCollections() {
|
||||
return fb.currentUser !== null
|
||||
? fb.currentCollections
|
||||
: this.$store.state.postwoman.collections
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async createCollectionGist() {
|
||||
await this.$axios
|
||||
.$post(
|
||||
"https://api.github.com/gists",
|
||||
{
|
||||
files: {
|
||||
"hoppscotch-collections.json": {
|
||||
content: this.getJSONCollection(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `token ${fb.currentUser.accessToken}`,
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
},
|
||||
}
|
||||
)
|
||||
.then((res) => {
|
||||
this.$toast.success(this.$t("gist_created"), {
|
||||
icon: "done",
|
||||
})
|
||||
window.open(res.html_url)
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.error(this.$t("something_went_wrong"), {
|
||||
icon: "error",
|
||||
})
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
async readCollectionGist() {
|
||||
const gist = prompt(this.$t("enter_gist_url"))
|
||||
if (!gist) return
|
||||
await this.$axios
|
||||
.$get(`https://api.github.com/gists/${gist.split("/").pop()}`, {
|
||||
headers: {
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
},
|
||||
})
|
||||
.then(({ files }) => {
|
||||
const collections = JSON.parse(Object.values(files)[0].content)
|
||||
this.$store.commit("postwoman/replaceCollections", {
|
||||
data: collections,
|
||||
flag: "rest",
|
||||
})
|
||||
this.fileImported()
|
||||
this.syncToFBCollections()
|
||||
})
|
||||
.catch((error) => {
|
||||
this.failedImport()
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
hideModal() {
|
||||
this.mode = "import_export"
|
||||
this.mySelectedCollectionID = undefined
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
openDialogChooseFileToReplaceWith() {
|
||||
this.$refs.inputChooseFileToReplaceWith.click()
|
||||
},
|
||||
openDialogChooseFileToImportFrom() {
|
||||
this.$refs.inputChooseFileToImportFrom.click()
|
||||
},
|
||||
replaceWithJSON() {
|
||||
const reader = new FileReader()
|
||||
reader.onload = ({ target }) => {
|
||||
const content = target.result
|
||||
let collections = JSON.parse(content)
|
||||
if (collections[0]) {
|
||||
const [name, folders, requests] = Object.keys(collections[0])
|
||||
if (
|
||||
name === "name" &&
|
||||
folders === "folders" &&
|
||||
requests === "requests"
|
||||
) {
|
||||
// Do nothing
|
||||
}
|
||||
} else if (
|
||||
collections.info &&
|
||||
collections.info.schema.includes("v2.1.0")
|
||||
) {
|
||||
collections = [this.parsePostmanCollection(collections)]
|
||||
} else {
|
||||
this.failedImport()
|
||||
}
|
||||
if (this.collectionsType.type === "team-collections") {
|
||||
teamUtils
|
||||
.replaceWithJSON(
|
||||
this.$apollo,
|
||||
collections,
|
||||
this.collectionsType.selectedTeam.id
|
||||
)
|
||||
.then((status) => {
|
||||
if (status) {
|
||||
this.fileImported()
|
||||
} else {
|
||||
this.failedImport()
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
this.failedImport()
|
||||
})
|
||||
} else {
|
||||
this.$store.commit("postwoman/replaceCollections", {
|
||||
data: collections,
|
||||
flag: "rest",
|
||||
})
|
||||
this.fileImported()
|
||||
this.syncToFBCollections()
|
||||
}
|
||||
}
|
||||
reader.readAsText(this.$refs.inputChooseFileToReplaceWith.files[0])
|
||||
this.$refs.inputChooseFileToReplaceWith.value = ""
|
||||
},
|
||||
importFromJSON() {
|
||||
const reader = new FileReader()
|
||||
reader.onload = ({ target }) => {
|
||||
const content = target.result
|
||||
let collections = JSON.parse(content)
|
||||
if (collections[0]) {
|
||||
const [name, folders, requests] = Object.keys(collections[0])
|
||||
if (
|
||||
name === "name" &&
|
||||
folders === "folders" &&
|
||||
requests === "requests"
|
||||
) {
|
||||
// Do nothing
|
||||
}
|
||||
} else if (
|
||||
collections.info &&
|
||||
collections.info.schema.includes("v2.1.0")
|
||||
) {
|
||||
// replace the variables, postman uses {{var}}, Hoppscotch uses <<var>>
|
||||
collections = JSON.parse(
|
||||
content.replaceAll(/{{([a-z]+)}}/gi, "<<$1>>")
|
||||
)
|
||||
collections = [this.parsePostmanCollection(collections)]
|
||||
} else {
|
||||
this.failedImport()
|
||||
return
|
||||
}
|
||||
if (this.collectionsType.type === "team-collections") {
|
||||
teamUtils
|
||||
.importFromJSON(
|
||||
this.$apollo,
|
||||
collections,
|
||||
this.collectionsType.selectedTeam.id
|
||||
)
|
||||
.then((status) => {
|
||||
if (status) {
|
||||
this.$emit("update-team-collections")
|
||||
this.fileImported()
|
||||
} else {
|
||||
this.failedImport()
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
this.failedImport()
|
||||
})
|
||||
} else {
|
||||
this.$store.commit("postwoman/importCollections", {
|
||||
data: collections,
|
||||
flag: "rest",
|
||||
})
|
||||
this.syncToFBCollections()
|
||||
this.fileImported()
|
||||
}
|
||||
}
|
||||
reader.readAsText(this.$refs.inputChooseFileToImportFrom.files[0])
|
||||
this.$refs.inputChooseFileToImportFrom.value = ""
|
||||
},
|
||||
importFromMyCollections() {
|
||||
teamUtils
|
||||
.importFromMyCollections(
|
||||
this.$apollo,
|
||||
this.mySelectedCollectionID,
|
||||
this.collectionsType.selectedTeam.id
|
||||
)
|
||||
.then((success) => {
|
||||
if (success) {
|
||||
this.fileImported()
|
||||
this.$emit("update-team-collections")
|
||||
} else {
|
||||
this.failedImport()
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
this.failedImport()
|
||||
})
|
||||
},
|
||||
async getJSONCollection() {
|
||||
if (this.collectionsType.type === "my-collections") {
|
||||
this.collectionJson = JSON.stringify(
|
||||
this.$store.state.postwoman.collections,
|
||||
null,
|
||||
2
|
||||
)
|
||||
} else {
|
||||
this.collectionJson = await teamUtils.exportAsJSON(
|
||||
this.$apollo,
|
||||
this.collectionsType.selectedTeam.id
|
||||
)
|
||||
}
|
||||
return this.collectionJson
|
||||
},
|
||||
exportJSON() {
|
||||
let text = this.collectionJson
|
||||
text = text.replace(/\n/g, "\r\n")
|
||||
const blob = new Blob([text], {
|
||||
type: "text/json",
|
||||
})
|
||||
const anchor = document.createElement("a")
|
||||
anchor.download = "hoppscotch-collection.json"
|
||||
anchor.href = window.URL.createObjectURL(blob)
|
||||
anchor.target = "_blank"
|
||||
anchor.style.display = "none"
|
||||
document.body.appendChild(anchor)
|
||||
anchor.click()
|
||||
document.body.removeChild(anchor)
|
||||
this.$toast.success(this.$t("download_started"), {
|
||||
icon: "done",
|
||||
})
|
||||
},
|
||||
syncCollections() {
|
||||
this.$store.commit("postwoman/replaceCollections", {
|
||||
data: fb.currentCollections,
|
||||
flag: "rest",
|
||||
})
|
||||
this.fileImported()
|
||||
},
|
||||
syncToFBCollections() {
|
||||
if (fb.currentUser !== null && this.SYNC_COLLECTIONS) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(JSON.stringify(this.$store.state.postwoman.collections)),
|
||||
"collections"
|
||||
)
|
||||
}
|
||||
},
|
||||
fileImported() {
|
||||
this.$toast.info(this.$t("file_imported"), {
|
||||
icon: "folder_shared",
|
||||
})
|
||||
},
|
||||
failedImport() {
|
||||
this.$toast.error(this.$t("import_failed"), {
|
||||
icon: "error",
|
||||
})
|
||||
},
|
||||
parsePostmanCollection({ info, name, item }) {
|
||||
const postwomanCollection = {
|
||||
name: "",
|
||||
folders: [],
|
||||
requests: [],
|
||||
}
|
||||
|
||||
postwomanCollection.name = info ? info.name : name
|
||||
|
||||
if (item && item.length > 0) {
|
||||
for (const collectionItem of item) {
|
||||
if (collectionItem.request) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
postwomanCollection,
|
||||
"folders"
|
||||
)
|
||||
) {
|
||||
postwomanCollection.name = info ? info.name : name
|
||||
postwomanCollection.requests.push(
|
||||
this.parsePostmanRequest(collectionItem)
|
||||
)
|
||||
} else {
|
||||
postwomanCollection.name = name || ""
|
||||
postwomanCollection.requests.push(
|
||||
this.parsePostmanRequest(collectionItem)
|
||||
)
|
||||
}
|
||||
} else if (this.hasFolder(collectionItem)) {
|
||||
postwomanCollection.folders.push(
|
||||
this.parsePostmanCollection(collectionItem)
|
||||
)
|
||||
} else {
|
||||
postwomanCollection.requests.push(
|
||||
this.parsePostmanRequest(collectionItem)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return postwomanCollection
|
||||
},
|
||||
parsePostmanRequest({ name, request }) {
|
||||
const pwRequest = {
|
||||
url: "",
|
||||
path: "",
|
||||
method: "",
|
||||
auth: "",
|
||||
httpUser: "",
|
||||
httpPassword: "",
|
||||
passwordFieldType: "password",
|
||||
bearerToken: "",
|
||||
headers: [],
|
||||
params: [],
|
||||
bodyParams: [],
|
||||
rawParams: "",
|
||||
rawInput: false,
|
||||
contentType: "",
|
||||
requestType: "",
|
||||
name: "",
|
||||
}
|
||||
|
||||
pwRequest.name = name
|
||||
if (request.url) {
|
||||
const requestObjectUrl = request.url.raw.match(
|
||||
/^(.+:\/\/[^/]+|{[^/]+})(\/[^?]+|).*$/
|
||||
)
|
||||
if (requestObjectUrl) {
|
||||
pwRequest.url = requestObjectUrl[1]
|
||||
pwRequest.path = requestObjectUrl[2] ? requestObjectUrl[2] : ""
|
||||
}
|
||||
}
|
||||
pwRequest.method = request.method
|
||||
const itemAuth = request.auth ? request.auth : ""
|
||||
const authType = itemAuth ? itemAuth.type : ""
|
||||
if (authType === "basic") {
|
||||
pwRequest.auth = "Basic Auth"
|
||||
pwRequest.httpUser =
|
||||
itemAuth.basic[0].key === "username"
|
||||
? itemAuth.basic[0].value
|
||||
: itemAuth.basic[1].value
|
||||
pwRequest.httpPassword =
|
||||
itemAuth.basic[0].key === "password"
|
||||
? itemAuth.basic[0].value
|
||||
: itemAuth.basic[1].value
|
||||
} else if (authType === "oauth2") {
|
||||
pwRequest.auth = "OAuth 2.0"
|
||||
pwRequest.bearerToken =
|
||||
itemAuth.oauth2[0].key === "accessToken"
|
||||
? itemAuth.oauth2[0].value
|
||||
: itemAuth.oauth2[1].value
|
||||
} else if (authType === "bearer") {
|
||||
pwRequest.auth = "Bearer Token"
|
||||
pwRequest.bearerToken = itemAuth.bearer[0].value
|
||||
}
|
||||
const requestObjectHeaders = request.header
|
||||
if (requestObjectHeaders) {
|
||||
pwRequest.headers = requestObjectHeaders
|
||||
for (const header of pwRequest.headers) {
|
||||
delete header.name
|
||||
delete header.type
|
||||
}
|
||||
}
|
||||
if (request.url) {
|
||||
const requestObjectParams = request.url.query
|
||||
if (requestObjectParams) {
|
||||
pwRequest.params = requestObjectParams
|
||||
for (const param of pwRequest.params) {
|
||||
delete param.disabled
|
||||
}
|
||||
}
|
||||
}
|
||||
if (request.body) {
|
||||
if (request.body.mode === "urlencoded") {
|
||||
const params = request.body.urlencoded
|
||||
pwRequest.bodyParams = params || []
|
||||
for (const param of pwRequest.bodyParams) {
|
||||
delete param.type
|
||||
}
|
||||
} else if (request.body.mode === "raw") {
|
||||
pwRequest.rawInput = true
|
||||
pwRequest.rawParams = request.body.raw
|
||||
}
|
||||
}
|
||||
return pwRequest
|
||||
},
|
||||
hasFolder(item) {
|
||||
return Object.prototype.hasOwnProperty.call(item, "item")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
262
components/collections/SaveRequest.vue
Normal file
@@ -0,0 +1,262 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("save_request_as") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("token_req_name") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="requestData.name"
|
||||
type="text"
|
||||
@keyup.enter="saveRequestAs"
|
||||
/>
|
||||
<label for="selectLabel">Select location</label>
|
||||
<!-- <input readonly :value="path" /> -->
|
||||
<Collections
|
||||
:picked="picked"
|
||||
:save-request="true"
|
||||
@select="onSelect"
|
||||
@update-collection="collectionsType.type = $event"
|
||||
@update-coll-type="onUpdateCollType"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="saveRequestAs">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
import { getSettingSubject } from "~/newstore/settings"
|
||||
import * as teamUtils from "~/helpers/teams/utils"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
editingRequest: { type: Object, default: () => {} },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultRequestName: "Untitled Request",
|
||||
path: "Path will appear here",
|
||||
requestData: {
|
||||
name: undefined,
|
||||
collectionIndex: undefined,
|
||||
folderName: undefined,
|
||||
requestIndex: undefined,
|
||||
},
|
||||
collectionsType: {
|
||||
type: "my-collections",
|
||||
selectedTeam: undefined,
|
||||
},
|
||||
picked: null,
|
||||
}
|
||||
},
|
||||
subscriptions() {
|
||||
return {
|
||||
SYNC_COLLECTIONS: getSettingSubject("syncCollections"),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
folders() {
|
||||
const collections = this.$store.state.postwoman.collections
|
||||
const collectionIndex = this.$data.requestData.collectionIndex
|
||||
const userSelectedAnyCollection = collectionIndex !== undefined
|
||||
if (!userSelectedAnyCollection) return []
|
||||
|
||||
const noCollectionAvailable = collections[collectionIndex] !== undefined
|
||||
if (!noCollectionAvailable) return []
|
||||
|
||||
return getFolderNames(collections[collectionIndex].folders, [])
|
||||
},
|
||||
requests() {
|
||||
const collections = this.$store.state.postwoman.collections
|
||||
const collectionIndex = this.$data.requestData.collectionIndex
|
||||
const folderName = this.$data.requestData.folderName
|
||||
|
||||
const userSelectedAnyCollection = collectionIndex !== undefined
|
||||
if (!userSelectedAnyCollection) {
|
||||
return []
|
||||
}
|
||||
|
||||
const userSelectedAnyFolder =
|
||||
folderName !== undefined && folderName !== ""
|
||||
|
||||
if (userSelectedAnyFolder) {
|
||||
const collection = collections[collectionIndex]
|
||||
const folder = findFolder(folderName, collection)
|
||||
return folder.requests
|
||||
} else {
|
||||
const collection = collections[collectionIndex]
|
||||
const noCollectionAvailable = collection !== undefined
|
||||
|
||||
if (!noCollectionAvailable) {
|
||||
return []
|
||||
}
|
||||
|
||||
return collection.requests
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
"requestData.collectionIndex": function resetFolderAndRequestIndex() {
|
||||
// if user has chosen some folder, than selected other collection, which doesn't have any folders
|
||||
// than `requestUpdateData.folderName` won't be reseted
|
||||
this.$data.requestData.folderName = undefined
|
||||
this.$data.requestData.requestIndex = undefined
|
||||
},
|
||||
"requestData.folderName": function resetRequestIndex() {
|
||||
this.$data.requestData.requestIndex = undefined
|
||||
},
|
||||
editingRequest({ name }) {
|
||||
this.$data.requestData.name = name || this.$data.defaultRequestName
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onUpdateCollType(newCollType) {
|
||||
this.collectionsType = newCollType
|
||||
},
|
||||
onSelect({ picked }) {
|
||||
this.picked = picked
|
||||
},
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && this.SYNC_COLLECTIONS) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(JSON.stringify(this.$store.state.postwoman.collections)),
|
||||
"collections"
|
||||
)
|
||||
}
|
||||
},
|
||||
saveRequestAs() {
|
||||
if (this.picked == null) {
|
||||
this.$toast.error(this.$t("select_collection"), {
|
||||
icon: "error",
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.$data.requestData.name.length === 0) {
|
||||
this.$toast.error(this.$t("empty_req_name"), {
|
||||
icon: "error",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const requestUpdated = {
|
||||
...this.$props.editingRequest,
|
||||
name: this.$data.requestData.name,
|
||||
collection: this.$data.requestData.collectionIndex,
|
||||
}
|
||||
|
||||
if (this.picked.pickedType === "my-request") {
|
||||
this.$store.commit("postwoman/saveRequestAs", {
|
||||
request: requestUpdated,
|
||||
collectionIndex: this.picked.collectionIndex,
|
||||
folderName: this.picked.folderName,
|
||||
requestIndex: this.picked.requestIndex,
|
||||
flag: "rest",
|
||||
})
|
||||
|
||||
this.syncCollections()
|
||||
} else if (this.picked.pickedType === "my-folder") {
|
||||
this.$store.commit("postwoman/saveRequestAs", {
|
||||
request: requestUpdated,
|
||||
collectionIndex: this.picked.collectionIndex,
|
||||
folderName: this.picked.folderName,
|
||||
flag: "rest",
|
||||
})
|
||||
|
||||
this.syncCollections()
|
||||
} else if (this.picked.pickedType === "my-collection") {
|
||||
this.$store.commit("postwoman/saveRequestAs", {
|
||||
request: requestUpdated,
|
||||
collectionIndex: this.picked.collectionIndex,
|
||||
flag: "rest",
|
||||
})
|
||||
|
||||
this.syncCollections()
|
||||
} else if (this.picked.pickedType === "teams-request") {
|
||||
teamUtils.overwriteRequestTeams(
|
||||
this.$apollo,
|
||||
JSON.stringify(requestUpdated),
|
||||
requestUpdated.name,
|
||||
this.picked.requestID
|
||||
)
|
||||
} else if (this.picked.pickedType === "teams-folder") {
|
||||
teamUtils.saveRequestAsTeams(
|
||||
this.$apollo,
|
||||
JSON.stringify(requestUpdated),
|
||||
requestUpdated.name,
|
||||
this.collectionsType.selectedTeam.id,
|
||||
this.picked.folderID
|
||||
)
|
||||
} else if (this.picked.pickedType === "teams-collection") {
|
||||
teamUtils.saveRequestAsTeams(
|
||||
this.$apollo,
|
||||
JSON.stringify(requestUpdated),
|
||||
requestUpdated.name,
|
||||
this.collectionsType.selectedTeam.id,
|
||||
this.picked.collectionID
|
||||
)
|
||||
}
|
||||
this.$toast.success("Requested added", {
|
||||
icon: "done",
|
||||
})
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
function getFolderNames(folders, namesList, folderName = "") {
|
||||
if (folders.length) {
|
||||
folders.forEach((folder) => {
|
||||
namesList.push(folderName + folder.name)
|
||||
if (folder.folders && folder.folders.length) {
|
||||
getFolderNames(folder.folders, namesList, folder.name + "/")
|
||||
}
|
||||
})
|
||||
}
|
||||
return namesList
|
||||
}
|
||||
|
||||
function findFolder(folderName, currentFolder) {
|
||||
let selectedFolder
|
||||
let result
|
||||
|
||||
if (folderName === currentFolder.name) {
|
||||
return currentFolder
|
||||
}
|
||||
|
||||
for (let i = 0; i < currentFolder.folders.length; i++) {
|
||||
selectedFolder = currentFolder.folders[i]
|
||||
|
||||
result = findFolder(folderName, selectedFolder)
|
||||
|
||||
if (result !== false) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
</script>
|
||||
@@ -1,83 +0,0 @@
|
||||
<template>
|
||||
<modal v-if="show" @close="show = false">
|
||||
<div slot="header">
|
||||
<ul>
|
||||
<li>
|
||||
<div class="flex-wrap">
|
||||
<h3 class="title">{{ $t("new_folder") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div slot="body">
|
||||
<ul>
|
||||
<li>
|
||||
<input
|
||||
type="text"
|
||||
v-model="name"
|
||||
:placeholder="$t('my_new_folder')"
|
||||
@keyup.enter="addNewFolder"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="flex-wrap">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="addNewFolder">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
collection: Object,
|
||||
collectionIndex: Number,
|
||||
},
|
||||
components: {
|
||||
modal: () => import("~/components/ui/modal"),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addNewFolder() {
|
||||
this.$store.commit("postwoman/addNewFolder", {
|
||||
folder: { name: this.$data.name },
|
||||
collectionIndex: this.$props.collectionIndex,
|
||||
})
|
||||
this.hideModal()
|
||||
this.syncCollections()
|
||||
},
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(JSON.parse(JSON.stringify(this.$store.state.postwoman.collections)))
|
||||
}
|
||||
}
|
||||
},
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,141 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex-wrap">
|
||||
<button class="icon" @click="toggleShowChildren">
|
||||
<i class="material-icons" v-show="!showChildren">arrow_right</i>
|
||||
<i class="material-icons" v-show="showChildren">arrow_drop_down</i>
|
||||
<i class="material-icons">folder</i>
|
||||
<span>{{ collection.name }}</span>
|
||||
</button>
|
||||
<div>
|
||||
<button
|
||||
v-if="doc"
|
||||
class="icon"
|
||||
@click="$emit('select-collection')"
|
||||
v-tooltip.left="$t('import')"
|
||||
>
|
||||
<i class="material-icons">topic</i>
|
||||
</button>
|
||||
<v-popover>
|
||||
<button class="tooltip-target icon" v-tooltip.left="$t('more')">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button class="icon" @click="$emit('add-folder')" v-close-popover>
|
||||
<i class="material-icons">create_new_folder</i>
|
||||
<span>{{ $t("new_folder") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="icon" @click="$emit('edit-collection')" v-close-popover>
|
||||
<i class="material-icons">create</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="icon" @click="removeCollection" v-close-popover>
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-show="showChildren">
|
||||
<ul>
|
||||
<li v-for="(folder, index) in collection.folders" :key="folder.name">
|
||||
<folder
|
||||
:folder="folder"
|
||||
:folderIndex="index"
|
||||
:collection-index="collectionIndex"
|
||||
:doc="doc"
|
||||
@edit-folder="editFolder(collectionIndex, folder, index)"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="collection.folders.length === 0 && collection.requests.length === 0">
|
||||
<label>{{ $t("collection_empty") }}</label>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li v-for="(request, index) in collection.requests" :key="index">
|
||||
<request
|
||||
:request="request"
|
||||
:collection-index="collectionIndex"
|
||||
:folder-index="-1"
|
||||
:request-index="index"
|
||||
:doc="doc"
|
||||
@edit-request="
|
||||
$emit('edit-request', {
|
||||
request,
|
||||
collectionIndex,
|
||||
folderIndex: undefined,
|
||||
requestIndex: index,
|
||||
})
|
||||
"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
ul {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
ul li {
|
||||
display: flex;
|
||||
margin-left: 32px;
|
||||
border-left: 1px solid var(--brd-color);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
components: {
|
||||
folder: () => import("./folder"),
|
||||
request: () => import("./request"),
|
||||
},
|
||||
props: {
|
||||
collectionIndex: Number,
|
||||
collection: Object,
|
||||
doc: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showChildren: false,
|
||||
selectedFolder: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(JSON.parse(JSON.stringify(this.$store.state.postwoman.collections)))
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleShowChildren() {
|
||||
this.showChildren = !this.showChildren
|
||||
},
|
||||
removeCollection() {
|
||||
if (!confirm("Are you sure you want to remove this Collection?")) return
|
||||
this.$store.commit("postwoman/removeCollection", {
|
||||
collectionIndex: this.collectionIndex,
|
||||
})
|
||||
this.syncCollections()
|
||||
},
|
||||
editFolder(collectionIndex, folder, folderIndex) {
|
||||
this.$emit("edit-folder", { collectionIndex, folder, folderIndex })
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,81 +0,0 @@
|
||||
<template>
|
||||
<modal v-if="show" @close="show = false">
|
||||
<div slot="header">
|
||||
<ul>
|
||||
<li>
|
||||
<div class="flex-wrap">
|
||||
<h3 class="title">{{ $t("edit_folder") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div slot="body">
|
||||
<ul>
|
||||
<li>
|
||||
<input type="text" v-model="name" :placeholder="folder.name" @keyup.enter="editFolder" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="flex-wrap">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="editFolder">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
collection: Object,
|
||||
collectionIndex: Number,
|
||||
folder: Object,
|
||||
folderIndex: Number,
|
||||
},
|
||||
components: {
|
||||
modal: () => import("~/components/ui/modal"),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(JSON.parse(JSON.stringify(this.$store.state.postwoman.collections)))
|
||||
}
|
||||
}
|
||||
},
|
||||
editFolder() {
|
||||
this.$store.commit("postwoman/editFolder", {
|
||||
collectionIndex: this.$props.collectionIndex,
|
||||
folder: { ...this.$props.folder, name: this.$data.name },
|
||||
folderIndex: this.$props.folderIndex,
|
||||
})
|
||||
this.hideModal()
|
||||
this.syncCollections()
|
||||
},
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,149 +0,0 @@
|
||||
<template>
|
||||
<modal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<ul>
|
||||
<li>
|
||||
<div class="flex-wrap">
|
||||
<h3 class="title">{{ $t("edit_request") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div slot="body">
|
||||
<ul>
|
||||
<li>
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
type="text"
|
||||
id="selectLabel"
|
||||
v-model="requestUpdateData.name"
|
||||
@keyup.enter="saveRequest"
|
||||
:placeholder="request.name"
|
||||
/>
|
||||
<label for="selectCollection">{{ $t("collection") }}</label>
|
||||
<span class="select-wrapper">
|
||||
<select type="text" id="selectCollection" v-model="requestUpdateData.collectionIndex">
|
||||
<option :key="undefined" :value="undefined" hidden disabled selected>{{
|
||||
$t("current_collection")
|
||||
}}</option>
|
||||
<option
|
||||
v-for="(collection, index) in $store.state.postwoman.collections"
|
||||
:key="index"
|
||||
:value="index"
|
||||
>
|
||||
{{ collection.name }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
<label for="selectFolder">{{ $t("folder") }}</label>
|
||||
<span class="select-wrapper">
|
||||
<select type="text" id="selectFolder" v-model="requestUpdateData.folderIndex">
|
||||
<option :key="undefined" :value="undefined">/</option>
|
||||
<option v-for="(folder, index) in folders" :key="index" :value="index">
|
||||
{{ folder.name }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="flex-wrap">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="saveRequest">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
collectionIndex: Number,
|
||||
folderIndex: Number,
|
||||
request: Object,
|
||||
requestIndex: Number,
|
||||
},
|
||||
components: {
|
||||
modal: () => import("~/components/ui/modal"),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
requestUpdateData: {
|
||||
name: undefined,
|
||||
collectionIndex: undefined,
|
||||
folderIndex: undefined,
|
||||
},
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
"requestUpdateData.collectionIndex": function resetFolderIndex() {
|
||||
// if user choosen some folder, than selected other collection, which doesn't have any folders
|
||||
// than `requestUpdateData.folderIndex` won't be reseted
|
||||
this.$data.requestUpdateData.folderIndex = undefined
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
folders() {
|
||||
const userSelectedAnyCollection = this.$data.requestUpdateData.collectionIndex !== undefined
|
||||
if (!userSelectedAnyCollection) return []
|
||||
|
||||
return this.$store.state.postwoman.collections[this.$data.requestUpdateData.collectionIndex]
|
||||
.folders
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(JSON.parse(JSON.stringify(this.$store.state.postwoman.collections)))
|
||||
}
|
||||
}
|
||||
},
|
||||
saveRequest() {
|
||||
const userSelectedAnyCollection = this.$data.requestUpdateData.collectionIndex !== undefined
|
||||
|
||||
const requestUpdated = {
|
||||
...this.$props.request,
|
||||
name: this.$data.requestUpdateData.name || this.$props.request.name,
|
||||
collection: userSelectedAnyCollection
|
||||
? this.$data.requestUpdateData.collectionIndex
|
||||
: this.$props.collectionIndex,
|
||||
folder: this.$data.requestUpdateData.folderIndex,
|
||||
}
|
||||
|
||||
// pass data separately to don't depend on request's collection, folder fields
|
||||
// probably, they should be deprecated because they don't describe request itself
|
||||
this.$store.commit("postwoman/editRequest", {
|
||||
requestOldCollectionIndex: this.$props.collectionIndex,
|
||||
requestOldFolderIndex: this.$props.folderIndex,
|
||||
requestOldIndex: this.$props.requestIndex,
|
||||
requestNew: requestUpdated,
|
||||
requestNewCollectionIndex: requestUpdated.collection,
|
||||
requestNewFolderIndex: requestUpdated.folder,
|
||||
})
|
||||
|
||||
this.hideModal()
|
||||
this.syncCollections()
|
||||
},
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,118 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex-wrap">
|
||||
<div>
|
||||
<button class="icon" @click="toggleShowChildren">
|
||||
<i class="material-icons" v-show="!showChildren">arrow_right</i>
|
||||
<i class="material-icons" v-show="showChildren">arrow_drop_down</i>
|
||||
<i class="material-icons">folder_open</i>
|
||||
<span>{{ folder.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<v-popover>
|
||||
<button class="tooltip-target icon" v-tooltip.left="$t('more')">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button class="icon" @click="editFolder" v-close-popover>
|
||||
<i class="material-icons">edit</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="icon" @click="removeFolder" v-close-popover>
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
|
||||
<div v-show="showChildren">
|
||||
<ul>
|
||||
<li v-for="(request, index) in folder.requests" :key="index">
|
||||
<request
|
||||
:request="request"
|
||||
:collection-index="collectionIndex"
|
||||
:folder-index="folderIndex"
|
||||
:request-index="index"
|
||||
:doc="doc"
|
||||
@edit-request="
|
||||
$emit('edit-request', {
|
||||
request,
|
||||
collectionIndex,
|
||||
folderIndex,
|
||||
requestIndex: index,
|
||||
})
|
||||
"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="folder.requests.length === 0">
|
||||
<label>{{ $t("folder_empty") }}</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
ul {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
ul li {
|
||||
display: flex;
|
||||
margin-left: 32px;
|
||||
border-left: 1px solid var(--brd-color);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
folder: Object,
|
||||
collectionIndex: Number,
|
||||
folderIndex: Number,
|
||||
doc: Boolean,
|
||||
},
|
||||
components: {
|
||||
request: () => import("./request"),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showChildren: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(JSON.parse(JSON.stringify(this.$store.state.postwoman.collections)))
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleShowChildren() {
|
||||
this.showChildren = !this.showChildren
|
||||
},
|
||||
selectRequest(request) {
|
||||
this.$store.commit("postwoman/selectRequest", { request })
|
||||
},
|
||||
removeFolder() {
|
||||
if (!confirm("Are you sure you want to remove this folder?")) return
|
||||
this.$store.commit("postwoman/removeFolder", {
|
||||
collectionIndex: this.collectionIndex,
|
||||
folderIndex: this.folderIndex,
|
||||
})
|
||||
this.syncCollections()
|
||||
},
|
||||
editFolder() {
|
||||
this.$emit("edit-folder")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,33 +1,27 @@
|
||||
<template>
|
||||
<modal v-if="show" @close="hideModal">
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<ul>
|
||||
<li>
|
||||
<div class="flex-wrap">
|
||||
<h3 class="title">{{ $t("new_collection") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("new_collection") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body">
|
||||
<ul>
|
||||
<li>
|
||||
<input
|
||||
type="text"
|
||||
v-model="name"
|
||||
:placeholder="$t('my_new_collection')"
|
||||
@keyup.enter="addNewCollection"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="$t('my_new_collection')"
|
||||
@keyup.enter="addNewCollection"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="flex-wrap">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
@@ -39,7 +33,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</modal>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -49,19 +43,21 @@ export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
components: {
|
||||
modal: () => import("~/components/ui/modal"),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: undefined,
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null) {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(JSON.parse(JSON.stringify(this.$store.state.postwoman.collections)))
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -72,13 +68,14 @@ export default {
|
||||
}
|
||||
this.$store.commit("postwoman/addNewCollection", {
|
||||
name: this.$data.name,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.$emit("hide-modal")
|
||||
this.syncCollections()
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
this.$data.name = undefined
|
||||
},
|
||||
},
|
||||
}
|
||||
82
components/collections/graphql/AddFolder.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="$emit('hide-modal')">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("new_folder") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="$t('my_new_folder')"
|
||||
@keyup.enter="addFolder"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="addFolder">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
folder: { type: Object, default: () => {} },
|
||||
folderPath: { type: String, default: null },
|
||||
collectionIndex: { type: Number, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
addFolder() {
|
||||
this.$emit("add-folder", {
|
||||
name: this.name,
|
||||
folder: this.folder,
|
||||
path: this.folderPath || `${this.collectionIndex}`,
|
||||
})
|
||||
this.syncCollections()
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
203
components/collections/graphql/Collection.vue
Normal file
@@ -0,0 +1,203 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:class="[
|
||||
'row-wrapper transition duration-150 ease-in-out',
|
||||
{ 'bg-bgDarkColor': dragging },
|
||||
]"
|
||||
@dragover.prevent
|
||||
@drop.prevent="dropEvent"
|
||||
@dragover="dragging = true"
|
||||
@drop="dragging = false"
|
||||
@dragleave="dragging = false"
|
||||
@dragend="dragging = false"
|
||||
>
|
||||
<button class="icon" @click="toggleShowChildren">
|
||||
<i v-show="!showChildren && !isFiltered" class="material-icons"
|
||||
>arrow_right</i
|
||||
>
|
||||
<i v-show="showChildren || isFiltered" class="material-icons"
|
||||
>arrow_drop_down</i
|
||||
>
|
||||
<i class="material-icons">folder</i>
|
||||
<span>{{ collection.name }}</span>
|
||||
</button>
|
||||
<div>
|
||||
<button
|
||||
v-if="doc"
|
||||
v-tooltip.left="$t('import')"
|
||||
class="icon"
|
||||
@click="$emit('select-collection')"
|
||||
>
|
||||
<i class="material-icons">topic</i>
|
||||
</button>
|
||||
<v-popover>
|
||||
<button v-tooltip.left="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="
|
||||
$emit('add-folder', {
|
||||
folder: collection,
|
||||
path: `${collectionIndex}`,
|
||||
})
|
||||
"
|
||||
>
|
||||
<i class="material-icons">create_new_folder</i>
|
||||
<span>{{ $t("new_folder") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="$emit('edit-collection')"
|
||||
>
|
||||
<i class="material-icons">create</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="confirmRemove = true"
|
||||
>
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="showChildren || isFiltered">
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(folder, index) in collection.folders"
|
||||
:key="folder.name"
|
||||
class="ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsGraphqlFolder
|
||||
:folder="folder"
|
||||
:folder-index="index"
|
||||
:folder-path="`${collectionIndex}/${index}`"
|
||||
:collection-index="collectionIndex"
|
||||
:doc="doc"
|
||||
:is-filtered="isFiltered"
|
||||
@add-folder="$emit('add-folder', $event)"
|
||||
@edit-folder="$emit('edit-folder', $event)"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(request, index) in collection.requests"
|
||||
:key="index"
|
||||
class="ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsGraphqlRequest
|
||||
:request="request"
|
||||
:collection-index="collectionIndex"
|
||||
:folder-index="-1"
|
||||
:folder-name="collection.name"
|
||||
:request-index="index"
|
||||
:doc="doc"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li
|
||||
v-if="
|
||||
collection.folders.length === 0 && collection.requests.length === 0
|
||||
"
|
||||
class="flex ml-8 border-l border-brdColor"
|
||||
>
|
||||
<p class="info">
|
||||
<i class="material-icons">not_interested</i>
|
||||
{{ $t("collection_empty") }}
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_collection')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeCollection"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
collectionIndex: { type: Number, default: null },
|
||||
collection: { type: Object, default: () => {} },
|
||||
doc: Boolean,
|
||||
isFiltered: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showChildren: false,
|
||||
dragging: false,
|
||||
selectedFolder: {},
|
||||
confirmRemove: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleShowChildren() {
|
||||
this.showChildren = !this.showChildren
|
||||
},
|
||||
removeCollection() {
|
||||
this.$store.commit("postwoman/removeCollection", {
|
||||
collectionIndex: this.collectionIndex,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
})
|
||||
this.syncCollections()
|
||||
},
|
||||
dropEvent({ dataTransfer }) {
|
||||
this.dragging = !this.dragging
|
||||
const oldCollectionIndex = dataTransfer.getData("oldCollectionIndex")
|
||||
const oldFolderIndex = dataTransfer.getData("oldFolderIndex")
|
||||
const oldFolderName = dataTransfer.getData("oldFolderName")
|
||||
const requestIndex = dataTransfer.getData("requestIndex")
|
||||
const flag = "graphql"
|
||||
this.$store.commit("postwoman/moveRequest", {
|
||||
oldCollectionIndex,
|
||||
newCollectionIndex: this.$props.collectionIndex,
|
||||
newFolderIndex: -1,
|
||||
newFolderName: this.$props.collection.name,
|
||||
oldFolderIndex,
|
||||
oldFolderName,
|
||||
requestIndex,
|
||||
flag,
|
||||
})
|
||||
this.syncCollections()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,33 +1,27 @@
|
||||
<template>
|
||||
<modal v-if="show" @close="hideModal">
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<ul>
|
||||
<li>
|
||||
<div class="flex-wrap">
|
||||
<h3 class="title">{{ $t("edit_collection") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_collection") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body">
|
||||
<ul>
|
||||
<li>
|
||||
<input
|
||||
type="text"
|
||||
v-model="name"
|
||||
:placeholder="editingCollection.name"
|
||||
@keyup.enter="saveCollection"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="editingCollection.name"
|
||||
@keyup.enter="saveCollection"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="flex-wrap">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
@@ -39,7 +33,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</modal>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -48,22 +42,24 @@ import { fb } from "~/helpers/fb"
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
editingCollection: Object,
|
||||
editingCollectionIndex: Number,
|
||||
},
|
||||
components: {
|
||||
modal: () => import("~/components/ui/modal"),
|
||||
editingCollection: { type: Object, default: () => {} },
|
||||
editingCollectionIndex: { type: Number, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: undefined,
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null) {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(JSON.parse(JSON.stringify(this.$store.state.postwoman.collections)))
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -79,11 +75,13 @@ export default {
|
||||
this.$store.commit("postwoman/editCollection", {
|
||||
collection: collectionUpdated,
|
||||
collectionIndex: this.$props.editingCollectionIndex,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.$emit("hide-modal")
|
||||
this.syncCollections()
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
84
components/collections/graphql/EditFolder.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="$emit('hide-modal')">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_folder") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="folder.name"
|
||||
@keyup.enter="editFolder"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="editFolder">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
collectionIndex: { type: Number, default: null },
|
||||
folder: { type: Object, default: () => {} },
|
||||
folderIndex: { type: Number, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
editFolder() {
|
||||
this.$store.commit("postwoman/editFolder", {
|
||||
collectionIndex: this.$props.collectionIndex,
|
||||
folder: { ...this.$props.folder, name: this.$data.name },
|
||||
folderIndex: this.$props.folderIndex,
|
||||
folderName: this.$props.folder.name,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.syncCollections()
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
94
components/collections/graphql/EditRequest.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_request") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="requestUpdateData.name"
|
||||
type="text"
|
||||
:placeholder="request.name"
|
||||
@keyup.enter="saveRequest"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="saveRequest">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
collectionIndex: { type: Number, default: null },
|
||||
folderIndex: { type: Number, default: null },
|
||||
folderName: { type: String, default: null },
|
||||
request: { type: Object, default: () => {} },
|
||||
requestIndex: { type: Number, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
requestUpdateData: {
|
||||
name: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
saveRequest() {
|
||||
const requestUpdated = {
|
||||
...this.$props.request,
|
||||
name: this.$data.requestUpdateData.name || this.$props.request.name,
|
||||
}
|
||||
|
||||
this.$store.commit("postwoman/editRequest", {
|
||||
requestCollectionIndex: this.$props.collectionIndex,
|
||||
requestFolderName: this.$props.folderName,
|
||||
requestFolderIndex: this.$props.folderIndex,
|
||||
requestNew: requestUpdated,
|
||||
requestIndex: this.$props.requestIndex,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.syncCollections()
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.requestUpdateData = { name: null }
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
195
components/collections/graphql/Folder.vue
Normal file
@@ -0,0 +1,195 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:class="[
|
||||
'row-wrapper transition duration-150 ease-in-out',
|
||||
{ 'bg-bgDarkColor': dragging },
|
||||
]"
|
||||
@dragover.prevent
|
||||
@drop.prevent="dropEvent"
|
||||
@dragover="dragging = true"
|
||||
@drop="dragging = false"
|
||||
@dragleave="dragging = false"
|
||||
@dragend="dragging = false"
|
||||
>
|
||||
<div>
|
||||
<button class="icon" @click="toggleShowChildren">
|
||||
<i v-show="!showChildren && !isFiltered" class="material-icons"
|
||||
>arrow_right</i
|
||||
>
|
||||
<i v-show="showChildren || isFiltered" class="material-icons"
|
||||
>arrow_drop_down</i
|
||||
>
|
||||
<i class="material-icons">folder_open</i>
|
||||
<span>{{ folder.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<v-popover>
|
||||
<button v-tooltip.left="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="$emit('add-folder', { folder, path: folderPath })"
|
||||
>
|
||||
<i class="material-icons">create_new_folder</i>
|
||||
<span>{{ $t("new_folder") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="
|
||||
$emit('edit-folder', { folder, folderIndex, collectionIndex })
|
||||
"
|
||||
>
|
||||
<i class="material-icons">edit</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button v-close-popover class="icon" @click="confirmRemove = true">
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<div v-show="showChildren || isFiltered">
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(subFolder, subFolderIndex) in folder.folders"
|
||||
:key="subFolder.name"
|
||||
class="ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsGraphqlFolder
|
||||
:folder="subFolder"
|
||||
:folder-index="subFolderIndex"
|
||||
:folder-path="`${folderPath}/${subFolderIndex}`"
|
||||
:collection-index="collectionIndex"
|
||||
:doc="doc"
|
||||
:is-filtered="isFiltered"
|
||||
@add-folder="$emit('add-folder', $event)"
|
||||
@edit-folder="$emit('edit-folder', $event)"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(request, index) in folder.requests"
|
||||
:key="index"
|
||||
class="flex ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsGraphqlRequest
|
||||
:request="request"
|
||||
:collection-index="collectionIndex"
|
||||
:folder-index="folderIndex"
|
||||
:folder-name="folder.name"
|
||||
:request-index="index"
|
||||
:doc="doc"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul
|
||||
v-if="
|
||||
folder.folders &&
|
||||
folder.folders.length === 0 &&
|
||||
folder.requests &&
|
||||
folder.requests.length === 0
|
||||
"
|
||||
>
|
||||
<li class="flex ml-8 border-l border-brdColor">
|
||||
<p class="info">
|
||||
<i class="material-icons">not_interested</i>
|
||||
{{ $t("folder_empty") }}
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_folder')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeFolder"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
name: "Folder",
|
||||
props: {
|
||||
folder: { type: Object, default: () => {} },
|
||||
folderIndex: { type: Number, default: null },
|
||||
collectionIndex: { type: Number, default: null },
|
||||
folderPath: { type: String, default: null },
|
||||
doc: Boolean,
|
||||
isFiltered: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showChildren: false,
|
||||
dragging: false,
|
||||
confirmRemove: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleShowChildren() {
|
||||
this.showChildren = !this.showChildren
|
||||
},
|
||||
removeFolder() {
|
||||
this.$store.commit("postwoman/removeFolder", {
|
||||
collectionIndex: this.$props.collectionIndex,
|
||||
folderName: this.$props.folder.name,
|
||||
folderIndex: this.$props.folderIndex,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.syncCollections()
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
})
|
||||
},
|
||||
dropEvent({ dataTransfer }) {
|
||||
this.dragging = !this.dragging
|
||||
const oldCollectionIndex = dataTransfer.getData("oldCollectionIndex")
|
||||
const oldFolderIndex = dataTransfer.getData("oldFolderIndex")
|
||||
const oldFolderName = dataTransfer.getData("oldFolderName")
|
||||
const requestIndex = dataTransfer.getData("requestIndex")
|
||||
const flag = "graphql"
|
||||
|
||||
this.$store.commit("postwoman/moveRequest", {
|
||||
oldCollectionIndex,
|
||||
newCollectionIndex: this.$props.collectionIndex,
|
||||
newFolderIndex: this.$props.folderIndex,
|
||||
newFolderName: this.$props.folder.name,
|
||||
oldFolderIndex,
|
||||
oldFolderName,
|
||||
requestIndex,
|
||||
flag,
|
||||
})
|
||||
this.syncCollections()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
461
components/collections/graphql/ImportExport.vue
Normal file
@@ -0,0 +1,461 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("import_export") }} {{ $t("collections") }}</h3>
|
||||
<div>
|
||||
<v-popover>
|
||||
<button v-tooltip.left="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="readCollectionGist"
|
||||
>
|
||||
<i class="material-icons">assignment_returned</i>
|
||||
<span>{{ $t("import_from_gist") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-tooltip.bottom="{
|
||||
content: !fb.currentUser
|
||||
? $t('login_with_github_to') + $t('create_secret_gist')
|
||||
: fb.currentUser.provider !== 'github.com'
|
||||
? $t('login_with_github_to') + $t('create_secret_gist')
|
||||
: null,
|
||||
}"
|
||||
>
|
||||
<button
|
||||
v-close-popover
|
||||
:disabled="
|
||||
!fb.currentUser
|
||||
? true
|
||||
: fb.currentUser.provider !== 'github.com'
|
||||
? true
|
||||
: false
|
||||
"
|
||||
class="icon"
|
||||
@click="createCollectionGist"
|
||||
>
|
||||
<i class="material-icons">assignment_turned_in</i>
|
||||
<span>{{ $t("create_secret_gist") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<div class="flex flex-col items-start p-2">
|
||||
<span
|
||||
v-tooltip="{
|
||||
content: !fb.currentUser
|
||||
? $t('login_first')
|
||||
: $t('replace_current'),
|
||||
}"
|
||||
>
|
||||
<button
|
||||
:disabled="!fb.currentUser"
|
||||
class="icon"
|
||||
@click="syncCollections"
|
||||
>
|
||||
<i class="material-icons">folder_shared</i>
|
||||
<span>{{ $t("import_from_sync") }}</span>
|
||||
</button>
|
||||
</span>
|
||||
<button
|
||||
v-tooltip="$t('replace_current')"
|
||||
class="icon"
|
||||
@click="openDialogChooseFileToReplaceWith"
|
||||
>
|
||||
<i class="material-icons">create_new_folder</i>
|
||||
<span>{{ $t("replace_json") }}</span>
|
||||
<input
|
||||
ref="inputChooseFileToReplaceWith"
|
||||
type="file"
|
||||
style="display: none"
|
||||
accept="application/json"
|
||||
@change="replaceWithJSON"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
v-tooltip="$t('preserve_current')"
|
||||
class="icon"
|
||||
@click="openDialogChooseFileToImportFrom"
|
||||
>
|
||||
<i class="material-icons">folder_special</i>
|
||||
<span>{{ $t("import_json") }}</span>
|
||||
<input
|
||||
ref="inputChooseFileToImportFrom"
|
||||
type="file"
|
||||
style="display: none"
|
||||
accept="application/json"
|
||||
@change="importFromJSON"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="showJsonCode" class="row-wrapper">
|
||||
<textarea v-model="collectionJson" rows="8" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span>
|
||||
<SmartToggle :on="showJsonCode" @change="showJsonCode = $event">
|
||||
{{ $t("show_code") }}
|
||||
</SmartToggle>
|
||||
</span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button
|
||||
v-tooltip="$t('download_file')"
|
||||
class="icon primary"
|
||||
@click="exportJSON"
|
||||
>
|
||||
{{ $t("export") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fb,
|
||||
showJsonCode: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
collectionJson() {
|
||||
return JSON.stringify(
|
||||
this.$store.state.postwoman.collectionsGraphql,
|
||||
null,
|
||||
2
|
||||
)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async createCollectionGist() {
|
||||
await this.$axios
|
||||
.$post(
|
||||
"https://api.github.com/gists",
|
||||
{
|
||||
files: {
|
||||
"hoppscotch-collections.json": {
|
||||
content: this.collectionJson,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `token ${fb.currentUser.accessToken}`,
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
},
|
||||
}
|
||||
)
|
||||
.then((res) => {
|
||||
this.$toast.success(this.$t("gist_created"), {
|
||||
icon: "done",
|
||||
})
|
||||
window.open(res.html_url)
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.error(this.$t("something_went_wrong"), {
|
||||
icon: "error",
|
||||
})
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
async readCollectionGist() {
|
||||
const gist = prompt(this.$t("enter_gist_url"))
|
||||
if (!gist) return
|
||||
await this.$axios
|
||||
.$get(`https://api.github.com/gists/${gist.split("/").pop()}`, {
|
||||
headers: {
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
},
|
||||
})
|
||||
.then(({ files }) => {
|
||||
const collections = JSON.parse(Object.values(files)[0].content)
|
||||
this.$store.commit("postwoman/replaceCollections", {
|
||||
data: collections,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.fileImported()
|
||||
this.syncToFBCollections()
|
||||
})
|
||||
.catch((error) => {
|
||||
this.failedImport()
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
openDialogChooseFileToReplaceWith() {
|
||||
this.$refs.inputChooseFileToReplaceWith.click()
|
||||
},
|
||||
openDialogChooseFileToImportFrom() {
|
||||
this.$refs.inputChooseFileToImportFrom.click()
|
||||
},
|
||||
replaceWithJSON() {
|
||||
const reader = new FileReader()
|
||||
reader.onload = ({ target }) => {
|
||||
const content = target.result
|
||||
let collections = JSON.parse(content)
|
||||
if (collections[0]) {
|
||||
const [name, folders, requests] = Object.keys(collections[0])
|
||||
if (
|
||||
name === "name" &&
|
||||
folders === "folders" &&
|
||||
requests === "requests"
|
||||
) {
|
||||
// Do nothing
|
||||
}
|
||||
} else if (
|
||||
collections.info &&
|
||||
collections.info.schema.includes("v2.1.0")
|
||||
) {
|
||||
collections = [this.parsePostmanCollection(collections)]
|
||||
} else {
|
||||
this.failedImport()
|
||||
return
|
||||
}
|
||||
this.$store.commit("postwoman/replaceCollections", {
|
||||
data: collections,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.fileImported()
|
||||
this.syncToFBCollections()
|
||||
}
|
||||
reader.readAsText(this.$refs.inputChooseFileToReplaceWith.files[0])
|
||||
this.$refs.inputChooseFileToReplaceWith.value = ""
|
||||
},
|
||||
importFromJSON() {
|
||||
const reader = new FileReader()
|
||||
reader.onload = ({ target }) => {
|
||||
const content = target.result
|
||||
let collections = JSON.parse(content)
|
||||
if (collections[0]) {
|
||||
const [name, folders, requests] = Object.keys(collections[0])
|
||||
if (
|
||||
name === "name" &&
|
||||
folders === "folders" &&
|
||||
requests === "requests"
|
||||
) {
|
||||
// Do nothing
|
||||
}
|
||||
} else if (
|
||||
collections.info &&
|
||||
collections.info.schema.includes("v2.1.0")
|
||||
) {
|
||||
// replace the variables, postman uses {{var}}, Hoppscotch uses <<var>>
|
||||
collections = JSON.parse(
|
||||
content.replaceAll(/{{([a-z]+)}}/gi, "<<$1>>")
|
||||
)
|
||||
collections = [this.parsePostmanCollection(collections)]
|
||||
} else {
|
||||
this.failedImport()
|
||||
return
|
||||
}
|
||||
this.$store.commit("postwoman/importCollections", {
|
||||
data: collections,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.fileImported()
|
||||
this.syncToFBCollections()
|
||||
}
|
||||
reader.readAsText(this.$refs.inputChooseFileToImportFrom.files[0])
|
||||
this.$refs.inputChooseFileToImportFrom.value = ""
|
||||
},
|
||||
exportJSON() {
|
||||
let text = this.collectionJson
|
||||
text = text.replace(/\n/g, "\r\n")
|
||||
const blob = new Blob([text], {
|
||||
type: "text/json",
|
||||
})
|
||||
const anchor = document.createElement("a")
|
||||
anchor.download = "hoppscotch-collection.json"
|
||||
anchor.href = window.URL.createObjectURL(blob)
|
||||
anchor.target = "_blank"
|
||||
anchor.style.display = "none"
|
||||
document.body.appendChild(anchor)
|
||||
anchor.click()
|
||||
document.body.removeChild(anchor)
|
||||
this.$toast.success(this.$t("download_started"), {
|
||||
icon: "done",
|
||||
})
|
||||
},
|
||||
syncCollections() {
|
||||
this.$store.commit("postwoman/replaceCollections", {
|
||||
data: fb.currentGraphqlCollections,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.fileImported()
|
||||
},
|
||||
syncToFBCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
fileImported() {
|
||||
this.$toast.info(this.$t("file_imported"), {
|
||||
icon: "folder_shared",
|
||||
})
|
||||
},
|
||||
failedImport() {
|
||||
this.$toast.error(this.$t("import_failed"), {
|
||||
icon: "error",
|
||||
})
|
||||
},
|
||||
parsePostmanCollection({ info, name, item }) {
|
||||
const postwomanCollection = {
|
||||
name: "",
|
||||
folders: [],
|
||||
requests: [],
|
||||
}
|
||||
|
||||
postwomanCollection.name = info ? info.name : name
|
||||
|
||||
if (item && item.length > 0) {
|
||||
for (const collectionItem of item) {
|
||||
if (collectionItem.request) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
postwomanCollection,
|
||||
"folders"
|
||||
)
|
||||
) {
|
||||
postwomanCollection.name = info ? info.name : name
|
||||
postwomanCollection.requests.push(
|
||||
this.parsePostmanRequest(collectionItem)
|
||||
)
|
||||
} else {
|
||||
postwomanCollection.name = name || ""
|
||||
postwomanCollection.requests.push(
|
||||
this.parsePostmanRequest(collectionItem)
|
||||
)
|
||||
}
|
||||
} else if (this.hasFolder(collectionItem)) {
|
||||
postwomanCollection.folders.push(
|
||||
this.parsePostmanCollection(collectionItem)
|
||||
)
|
||||
} else {
|
||||
postwomanCollection.requests.push(
|
||||
this.parsePostmanRequest(collectionItem)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return postwomanCollection
|
||||
},
|
||||
parsePostmanRequest({ name, request }) {
|
||||
const pwRequest = {
|
||||
url: "",
|
||||
path: "",
|
||||
method: "",
|
||||
auth: "",
|
||||
httpUser: "",
|
||||
httpPassword: "",
|
||||
passwordFieldType: "password",
|
||||
bearerToken: "",
|
||||
headers: [],
|
||||
params: [],
|
||||
bodyParams: [],
|
||||
rawParams: "",
|
||||
rawInput: false,
|
||||
contentType: "",
|
||||
requestType: "",
|
||||
name: "",
|
||||
}
|
||||
|
||||
pwRequest.name = name
|
||||
const requestObjectUrl = request.url.raw.match(
|
||||
/^(.+:\/\/[^/]+|{[^/]+})(\/[^?]+|).*$/
|
||||
)
|
||||
if (requestObjectUrl) {
|
||||
pwRequest.url = requestObjectUrl[1]
|
||||
pwRequest.path = requestObjectUrl[2] ? requestObjectUrl[2] : ""
|
||||
}
|
||||
pwRequest.method = request.method
|
||||
const itemAuth = request.auth ? request.auth : ""
|
||||
const authType = itemAuth ? itemAuth.type : ""
|
||||
if (authType === "basic") {
|
||||
pwRequest.auth = "Basic Auth"
|
||||
pwRequest.httpUser =
|
||||
itemAuth.basic[0].key === "username"
|
||||
? itemAuth.basic[0].value
|
||||
: itemAuth.basic[1].value
|
||||
pwRequest.httpPassword =
|
||||
itemAuth.basic[0].key === "password"
|
||||
? itemAuth.basic[0].value
|
||||
: itemAuth.basic[1].value
|
||||
} else if (authType === "oauth2") {
|
||||
pwRequest.auth = "OAuth 2.0"
|
||||
pwRequest.bearerToken =
|
||||
itemAuth.oauth2[0].key === "accessToken"
|
||||
? itemAuth.oauth2[0].value
|
||||
: itemAuth.oauth2[1].value
|
||||
} else if (authType === "bearer") {
|
||||
pwRequest.auth = "Bearer Token"
|
||||
pwRequest.bearerToken = itemAuth.bearer[0].value
|
||||
}
|
||||
const requestObjectHeaders = request.header
|
||||
if (requestObjectHeaders) {
|
||||
pwRequest.headers = requestObjectHeaders
|
||||
for (const header of pwRequest.headers) {
|
||||
delete header.name
|
||||
delete header.type
|
||||
}
|
||||
}
|
||||
const requestObjectParams = request.url.query
|
||||
if (requestObjectParams) {
|
||||
pwRequest.params = requestObjectParams
|
||||
for (const param of pwRequest.params) {
|
||||
delete param.disabled
|
||||
}
|
||||
}
|
||||
if (request.body) {
|
||||
if (request.body.mode === "urlencoded") {
|
||||
const params = request.body.urlencoded
|
||||
pwRequest.bodyParams = params || []
|
||||
for (const param of pwRequest.bodyParams) {
|
||||
delete param.type
|
||||
}
|
||||
} else if (request.body.mode === "raw") {
|
||||
pwRequest.rawInput = true
|
||||
pwRequest.rawParams = request.body.raw
|
||||
}
|
||||
}
|
||||
return pwRequest
|
||||
},
|
||||
hasFolder(item) {
|
||||
return Object.prototype.hasOwnProperty.call(item, "item")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
123
components/collections/graphql/Request.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:class="[
|
||||
'row-wrapper transition duration-150 ease-in-out',
|
||||
{ 'bg-bgDarkColor': dragging },
|
||||
]"
|
||||
draggable="true"
|
||||
@dragstart="dragStart"
|
||||
@dragover.stop
|
||||
@dragleave="dragging = false"
|
||||
@dragend="dragging = false"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
v-tooltip="!doc ? $t('use_request') : ''"
|
||||
class="icon"
|
||||
@click="!doc ? selectRequest() : {}"
|
||||
>
|
||||
<i class="material-icons">description</i>
|
||||
<span>{{ request.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<v-popover>
|
||||
<button v-tooltip="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="
|
||||
$emit('edit-request', {
|
||||
collectionIndex,
|
||||
folderIndex,
|
||||
folderName,
|
||||
request,
|
||||
requestIndex,
|
||||
})
|
||||
"
|
||||
>
|
||||
<i class="material-icons">edit</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button v-close-popover class="icon" @click="confirmRemove = true">
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_request')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeRequest"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
request: { type: Object, default: () => {} },
|
||||
collectionIndex: { type: Number, default: null },
|
||||
folderIndex: { type: Number, default: null },
|
||||
folderName: { type: String, default: null },
|
||||
requestIndex: { type: Number, default: null },
|
||||
doc: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dragging: false,
|
||||
confirmRemove: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
selectRequest() {
|
||||
this.$store.commit("postwoman/selectGraphqlRequest", {
|
||||
request: this.request,
|
||||
})
|
||||
},
|
||||
dragStart({ dataTransfer }) {
|
||||
this.dragging = !this.dragging
|
||||
dataTransfer.setData("oldCollectionIndex", this.$props.collectionIndex)
|
||||
dataTransfer.setData("oldFolderIndex", this.$props.folderIndex)
|
||||
dataTransfer.setData("oldFolderName", this.$props.folderName)
|
||||
dataTransfer.setData("requestIndex", this.$props.requestIndex)
|
||||
},
|
||||
removeRequest() {
|
||||
this.$store.commit("postwoman/removeRequest", {
|
||||
collectionIndex: this.$props.collectionIndex,
|
||||
folderName: this.$props.folderName,
|
||||
requestIndex: this.$props.requestIndex,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
})
|
||||
this.confirmRemove = false
|
||||
this.syncCollections()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||