Compare commits
658 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a8c93d96b1 | |||
| 8886082ebf | |||
| 12432bee91 | |||
| 551cbee92c | |||
| 8702a28bcc | |||
| 90e89791f3 | |||
| 20298d3dd5 | |||
| 2bfc41b1c3 | |||
| 016c8307df | |||
| 6ec8afeb84 | |||
| 0396114665 | |||
| 24e0462d1a | |||
| f1d0809d2d | |||
| c80de38572 | |||
| b4b9caed83 | |||
| dc15328e13 | |||
| 5917b1a0e1 | |||
| ebd41a3163 | |||
| 3fdfa231b7 | |||
| dc076b15a8 | |||
| 76feb1f8c5 | |||
| 6b22f51a66 | |||
| 704f44338b | |||
| 942f28466e | |||
| 733d3d5c01 | |||
| 35bc677f03 | |||
| cd274038b5 | |||
| 47df888060 | |||
| a491528f80 | |||
| 9e25feb22f | |||
| 0a8aa4630b | |||
| 1237c1c965 | |||
| cf484129a5 | |||
| 8130afcf33 | |||
| bbe496fda9 | |||
| e32cf5a581 | |||
| 5f67e223b8 | |||
| 13f2bf29f0 | |||
| a66320a35f | |||
| 93a77d0ad1 | |||
| 97c281cff6 | |||
| 81d53d9f9e | |||
| 597492539f | |||
| 9d3f4c605e | |||
| 0c6d9869e5 | |||
| 262e226e30 | |||
| 853de04cf9 | |||
| 0def89422b | |||
| c1572b278f | |||
| 096f382a70 | |||
| c268191470 | |||
| b711f35c11 | |||
| e0b3c0a378 | |||
| eb80692ddf | |||
| 79cfac27f8 | |||
| e49c7f6fb2 | |||
| 3f500ba488 | |||
| 740b96305e | |||
| c9ad41d625 | |||
| adbe0a01bc | |||
| a3afb4b998 | |||
| bbaae9b030 | |||
| 12f72d8c17 | |||
| ecf77dfd1d | |||
| 68d2e9b937 | |||
| 95c1cfe868 | |||
| 0bc39536d1 | |||
| a7ddeb7b89 | |||
| 06eba8c545 | |||
| f4267bf3da | |||
| 5484cf182c | |||
| 02f2347b9a | |||
| eb1c0fd4d8 | |||
| 5a4408c6ff | |||
| 3a16957d29 | |||
| db17a1ffad | |||
| 33c570217c | |||
| e9373142da | |||
| 6d1690ed1c | |||
| 599b97cec6 | |||
| 6fa3a6cecb | |||
| 6efd572065 | |||
| 3441016907 | |||
| 99666f899c | |||
| c9f80a1bb1 | |||
| e27a115721 | |||
| 9625a2612f | |||
| 1efb45a752 | |||
| f2f0dd6f06 | |||
| 08ddaa213e | |||
| 2097dee792 | |||
| 079fcbe983 | |||
| 08fd972931 | |||
| d16db714a4 | |||
| b5d66b616d | |||
| d1f09d9dd1 | |||
| 7be2003991 | |||
| b313bf06cd | |||
| cb877e8866 | |||
| ee33484bfb | |||
| 51e3d247d0 | |||
| d94c76e95b | |||
| 243ffda643 | |||
| c327c5a7ca | |||
| ea7a029ef6 | |||
| 8e7f559745 | |||
| 0a413dde02 | |||
| 251ec388e5 | |||
| 2723394729 | |||
| 119f79bdc8 | |||
| ba764cd367 | |||
| f516006f54 | |||
| ab2436e34e | |||
| cf5169f3bb | |||
| 0f2157cc43 | |||
| e0d054eb14 | |||
| 5d294cffc6 | |||
| b61f408829 | |||
| 3cb9c43346 | |||
| bef8970070 | |||
| 2e7932a7be | |||
| 3ec7535709 | |||
| 3d582509c5 | |||
| e9de1e0961 | |||
| 0ae5442c53 | |||
| 517cff52d2 | |||
| 21ee4c431b | |||
| 7f9f43652d | |||
| 99ec04f3b8 | |||
| 25ecf0e07b | |||
| cdb1036762 | |||
| ce0b960578 | |||
| c60d570517 | |||
| 72fc7cc83b | |||
| e3200d15e7 | |||
| 04f30e0ebd | |||
| 02c3789b5d | |||
| 8d21fa09e4 | |||
| 9e027d937d | |||
| fc34012a09 | |||
| bb20e92bb0 | |||
| 9ed7d20a19 | |||
| a3a592039e | |||
| 82985d6a80 | |||
| 1403c48c0d | |||
| 3e25342012 | |||
| 0ef7d1fdba | |||
| e066ad3ac8 | |||
| 6e0f7137a1 | |||
| fad404da8d | |||
| 818c76597f | |||
| 908a2db558 | |||
| 7df995436b | |||
| ccda342db9 | |||
| 2edc8662ad | |||
| d342f87489 | |||
| e29a568f2a | |||
| e5f19a6405 | |||
| fb529f0d2b | |||
| 21d1df3802 | |||
| 9951ec5740 | |||
| cc0e5adf3a | |||
| b05541b68c | |||
| 06e734f44a | |||
| 8dc17f57b6 | |||
| 95b7fc4f05 | |||
| 041e32aec8 | |||
| 93771bc54d | |||
| e7949204fe | |||
| d0464ef12e | |||
| 096ebf230a | |||
| c26ff95352 | |||
| 988e624ec3 | |||
| 0905e7edd3 | |||
| 41e2a17ad2 | |||
| 01c6f63c0c | |||
| 4bb2147657 | |||
| b8bfee0eb5 | |||
| 2a37614688 | |||
| c66ba0cc17 | |||
| d6283b1b32 | |||
| 3cfb3042fa | |||
| 00ecaf7a0d | |||
| f53aaf6060 | |||
| 85cacdfbfe | |||
| af1956cc84 | |||
| 40e79ac282 | |||
| a5cb8f6deb | |||
| 7007af70f2 | |||
| 7e865623de | |||
| 73d308dc01 | |||
| f444fd280b | |||
| fa52606fca | |||
| 849fcff20e | |||
| 706ada8ff7 | |||
| fc46c98336 | |||
| d98fd66f57 | |||
| 0c76fd3b09 | |||
| c4e23bdd7a | |||
| f0407a2051 | |||
| 3c61e848a6 | |||
| 4712204c82 | |||
| 40422f1d03 | |||
| 4ea2cf1fd9 | |||
| ca6728cc16 | |||
| a8ef3e22f0 | |||
| 3f631b5937 | |||
| 090e5eea31 | |||
| 93e88e0d06 | |||
| bd0b10180d | |||
| d608fa2cfa | |||
| fba7b6dc0c | |||
| 14fe4f3c68 | |||
| cbb3d9bb86 | |||
| 782f542035 | |||
| e71e5ca5be | |||
| b8ae9f236c | |||
| 31026a77ac | |||
| 3679d31a29 | |||
| 3a0aa4a1dc | |||
| 7ffecf9206 | |||
| ea20bd5070 | |||
| c98d7aae37 | |||
| 21d27d223c | |||
| ea13aece21 | |||
| b0bb537501 | |||
| 75783345aa | |||
| 931e2565b6 | |||
| 2f6584378d | |||
| 519a580b7b | |||
| c99d62228f | |||
| 74d3c9366a | |||
| a3d452ab2a | |||
| 78a6fd4c70 | |||
| c9a56e8f3e | |||
| d28e1708c5 | |||
| e091072367 | |||
| 7b1032e898 | |||
| 855470ed25 | |||
| 631efd1adc | |||
| 2e227909a4 | |||
| e5c52625ad | |||
| 8f9f95fd84 | |||
| ff334d08e2 | |||
| 25b443a7c6 | |||
| 6724413ce9 | |||
| 684a615a07 | |||
| babceaff42 | |||
| c29e9ddfc6 | |||
| 0cd0bcf874 | |||
| 544a703df5 | |||
| 0b32692290 | |||
| d6a6104e1e | |||
| 0fc13c4db3 | |||
| 97f672eafe | |||
| 11cad2ddc7 | |||
| 2dbc9d8560 | |||
| 1b174cd4cf | |||
| 88afd5f341 | |||
| 666907fd6a | |||
| 0d41768634 | |||
| 1d21f73e25 | |||
| 3fc4dc5272 | |||
| 9681a8333e | |||
| 4f5d8f8df7 | |||
| a4961a71fe | |||
| 86c32ee136 | |||
| 2f8ffae81c | |||
| ec028bc34e | |||
| befed9560e | |||
| 902e31bf0c | |||
| 140dc5184f | |||
| 054594da4d | |||
| 15b0817745 | |||
| 8866cf227b | |||
| 32afadb0e4 | |||
| dbdb1af078 | |||
| 401ae6581e | |||
| c7c90826bb | |||
| 8266edb94d | |||
| c48cf07dca | |||
| 121af97f78 | |||
| 82fb62ac84 | |||
| 030a23aea2 | |||
| 46ff43af2b | |||
| da4b35903a | |||
| f54917bf03 | |||
| 60f00d7e6d | |||
| 941fd0eb34 | |||
| 3fe439a6d9 | |||
| 9a6aaa80c8 | |||
| dbe5fecb25 | |||
| 682a012e27 | |||
| 92231e6b4c | |||
| 4586d51818 | |||
| e786a2572a | |||
| e2c73c5c41 | |||
| a57a157ebf | |||
| 33ecf36bf0 | |||
| 18797162a0 | |||
| cbd8301c03 | |||
| 3c8533b230 | |||
| 1672456fba | |||
| 319bd70015 | |||
| 02d541e4fc | |||
| c9bf5a1c1a | |||
| ea52fb72b4 | |||
| ec1864dce2 | |||
| 96e8bfe469 | |||
| 43889aefb0 | |||
| b674d2366f | |||
| cecd7118be | |||
| 5e19526b55 | |||
| 76db47a83d | |||
| d6a721d577 | |||
| 9eb02f9bdb | |||
| a0886f5d04 | |||
| 3db3c06528 | |||
| f94c42b4fa | |||
| 29965dfc72 | |||
| 9ed094de56 | |||
| 7ffec31fde | |||
| 2911e65059 | |||
| c36d274867 | |||
| 00ce51961d | |||
| d300480cf9 | |||
| e24fa5381b | |||
| 6959b1836f | |||
| cd70eb0666 | |||
| 7cb92c773c | |||
| 624535c22a | |||
| 3cb9ef066b | |||
| 1cfeb9642c | |||
| b378b183af | |||
| b6af401d07 | |||
| e74a6ffffe | |||
| af9e7d9cf0 | |||
| 1197d85620 | |||
| 93cde287d9 | |||
| 039b57dee6 | |||
| 0036d85928 | |||
| f639b30cf4 | |||
| 373714c2ae | |||
| 3e805409b2 | |||
| 2d5b9c28ff | |||
| ca13953708 | |||
| 77dbe63c28 | |||
| d885f08aeb | |||
| 823bd945ca | |||
| 3f82d41f90 | |||
| eeb19579fb | |||
| 1ab98ddf85 | |||
| e8e864203d | |||
| 3a88c1df9f | |||
| 567402e276 | |||
| aacf65f51b | |||
| e5d8911eb4 | |||
| a57a162b8e | |||
| 5b2330e2c8 | |||
| e8af8096e0 | |||
| 7da80a0818 | |||
| d47e56e696 | |||
| 6dfbdc09b0 | |||
| 50125fa2b9 | |||
| 986516e0d6 | |||
| 2380c3c61d | |||
| e4a6003223 | |||
| 7657ab2c88 | |||
| e9fc738496 | |||
| 4250330412 | |||
| b4c471cd05 | |||
| 03f81b8e33 | |||
| 370f25a0a7 | |||
| f3bab6436f | |||
| 1753cbe26d | |||
| 8f15b544d5 | |||
| 35466fb767 | |||
| 22dcbf6b85 | |||
| 9629cfce81 | |||
| c1054fc3bb | |||
| bfbcdfc3b7 | |||
| 4a79576de0 | |||
| ad3f11728e | |||
| 079b45a3a4 | |||
| f4f7ceb54c | |||
| abfd132a2a | |||
| ce8fd55d78 | |||
| a318819eb2 | |||
| f49052a66b | |||
| f8695f8101 | |||
| 07fe34fefd | |||
| 0f9e4e37be | |||
| 393587fa62 | |||
| beb1c5fd4c | |||
| 523bb7ce4d | |||
| a27f6c1c75 | |||
| a227c85097 | |||
| 4b466a9889 | |||
| 99b42679f5 | |||
| 484ad8bb86 | |||
| ff5d529bdf | |||
| cc6871d80a | |||
| 7252fe47a8 | |||
| a99b19dbb3 | |||
| 8165491d9b | |||
| 9f1e8751ae | |||
| 68a36b0960 | |||
| 8dadd9dcb1 | |||
| 3f6b61ae7e | |||
| d56a006a1a | |||
| d6a03d17c7 | |||
| 9524050e21 | |||
| 3204855710 | |||
| 43b578a8f5 | |||
| ded4b65f58 | |||
| a1a10ed410 | |||
| 4faf0f416f | |||
| 2e6c188d62 | |||
| 5e12f8abc9 | |||
| 2bb898ee8f | |||
| 093f2a29d5 | |||
| 799a3de587 | |||
| 018fc44b03 | |||
| b788ba5c58 | |||
| 5ba12c7bfb | |||
| 8a1a17a271 | |||
| de334b1b59 | |||
| 53b94a9c5c | |||
| 6649767072 | |||
| 39d725762b | |||
| 17e1eacc2b | |||
| 702056e9c0 | |||
| 793201524a | |||
| 25cc887426 | |||
| 7f1d2b50f6 | |||
| 656e7087fc | |||
| 2a79a581e0 | |||
| 8e702b0cd4 | |||
| 6645a1fc5e | |||
| 292389fb82 | |||
| 4fe56cc9c2 | |||
| 483193dc14 | |||
| c75f4ab403 | |||
| 8c1dd853f9 | |||
| 300c08b243 | |||
| 39ea4c313f | |||
| 7e93905819 | |||
| 4499c3e0fc | |||
| 5f8ae8e26e | |||
| 95891885c1 | |||
| 775f49b2fc | |||
| 55ef0310ff | |||
| 5330955c0d | |||
| d4b771ddf8 | |||
| 04d9e1365d | |||
| 94871082a6 | |||
| df4f8728f3 | |||
| 7646c156ad | |||
| 7b7e4f9fa0 | |||
| 1dde38340e | |||
| 0641655738 | |||
| 2ab98d891b | |||
| a57108e4c9 | |||
| 4e4394fc9c | |||
| bbadbdfc1c | |||
| 7f0f41d9f8 | |||
| 650681fcb3 | |||
| b4bd129385 | |||
| c281b35e05 | |||
| 9306eb46c6 | |||
| 4b7ba57839 | |||
| 0ec8aa7ced | |||
| 3a1f900402 | |||
| be0254304e | |||
| f0b3176cd6 | |||
| 3d297bd2a6 | |||
| 2fece57a4a | |||
| db5749b92b | |||
| a6146ddba4 | |||
| c1ac43b332 | |||
| 6d3ce09c41 | |||
| 0a63d0efab | |||
| 0ad1b4cf77 | |||
| 5a8a1a067e | |||
| 7da9cc61a0 | |||
| 105e695568 | |||
| a2e6cdb9cc | |||
| 7fe0c0e0a5 | |||
| 99a599e66a | |||
| 741ec3f462 | |||
| 8a5cb47ca6 | |||
| 7dbe23abbf | |||
| 93ef9b4092 | |||
| 3bd3dc9dc9 | |||
| 793f17d3f8 | |||
| 9b41108f6d | |||
| f765234fd1 | |||
| 94b4f254b2 | |||
| bd8b884d1f | |||
| 54a080ac32 | |||
| 51d1c012d6 | |||
| b7e7827555 | |||
| dcfd0f73ef | |||
| 6d6a10aacd | |||
| 47742f2f83 | |||
| 2959fb274a | |||
| 7538978f9f | |||
| ade59b1195 | |||
| e8348d47ee | |||
| 0f3ec0c0ce | |||
| 0f18b1dd1a | |||
| 2ed381e59b | |||
| 4778fe3f0e | |||
| 326a8d9e0c | |||
| a411104230 | |||
| ddec97099b | |||
| 0c5ad71932 | |||
| de279e33de | |||
| a0dd797174 | |||
| 841ea175e6 | |||
| 8e8cde5578 | |||
| 378f199a6d | |||
| 8b6918e738 | |||
| 1c4e9113ed | |||
| 0a208d9948 | |||
| d26a8912fd | |||
| cca61359f8 | |||
| 69c1effe2b | |||
| 8c77346688 | |||
| 22b93fedff | |||
| 4796651095 | |||
| 3c141b9e63 | |||
| f6a2d4a8ae | |||
| 250fb0ae33 | |||
| b7eb9e07e5 | |||
| 9fa414b3a3 | |||
| d3e1e65d82 | |||
| 30b67bfb2e | |||
| 0aef4e52e4 | |||
| 73845b1bc1 | |||
| f93e6983c8 | |||
| 28bbcb59a8 | |||
| 04d55687e9 | |||
| 431480f751 | |||
| ea8e17592d | |||
| 9bf0338869 | |||
| dd7c3dae74 | |||
| fbfa8a310c | |||
| e3aef1bda0 | |||
| b75c01c6c1 | |||
| dbfbda6d32 | |||
| 5da61ffd75 | |||
| 8094580e79 | |||
| 93fd208c09 | |||
| 19dc8dec0f | |||
| 3ae59f1ec7 | |||
| 1fe2f895d3 | |||
| 42230379f8 | |||
| fb5a492c7f | |||
| 595a01f040 | |||
| 500a0a84dc | |||
| 45be4dd6ea | |||
| 41ff2cb444 | |||
| f42013d91b | |||
| f2bf7c7dbf | |||
| aecf063c55 | |||
| 772bbaf09d | |||
| 2f81b4324a | |||
| c4162a5910 | |||
| 40e8e1573c | |||
| 8ae0f64b4d | |||
| c8469cb1a3 | |||
| f0f90a3653 | |||
| e89076af62 | |||
| f42928ca44 | |||
| 432b6bf2cd | |||
| 7f47ce0fbf | |||
| 1a4eef9817 | |||
| 9c7e2131a6 | |||
| 271ed1f080 | |||
| 30e40fa58d | |||
| 1866d1ccf8 | |||
| e8391638fa | |||
| 0cea9d255b | |||
| b088a529f2 | |||
| e4f301deda | |||
| 6387b4f844 | |||
| 05edec4492 | |||
| 2ccbbfcea8 | |||
| 378f5922b9 | |||
| 17d066fe9d | |||
| b6de9d2448 | |||
| 222f1afd24 | |||
| 2706bdf5aa | |||
| 560b6714f9 | |||
| 31f3a08945 | |||
| 25e54f9632 | |||
| 475217ff27 | |||
| f5155039cf | |||
| 671d3652e3 | |||
| 86040fbc93 | |||
| 9206be3c64 | |||
| 695e0c4206 | |||
| b2426c5a14 | |||
| e158933ae4 | |||
| de6005bdac | |||
| 83b24ffa19 | |||
| 6015e96f15 | |||
| df0d4b38b6 | |||
| 45ed5f3748 | |||
| fba2f5330f | |||
| f35fb3879b | |||
| caaaf3381d | |||
| d3a97946e3 | |||
| b0c78734ca | |||
| b2b5ab714b | |||
| c570a69b87 | |||
| 2ac1610173 | |||
| f6e72627c4 | |||
| 5f43d8ac2b | |||
| fe6a26bd87 | |||
| 5cc2e6fe6a | |||
| c4db75b585 | |||
| c0ae6eca18 | |||
| 878242d8fd | |||
| e6e93fa2c2 | |||
| 666107e135 | |||
| 1868f60948 | |||
| 6f464b884e | |||
| a008f5a745 | |||
| 9165e2cd6a | |||
| 825ea5297f | |||
| 6db7f99a3b | |||
| b50e23ca2c | |||
| 703c3d91b3 | |||
| 83a05d870c | |||
| 4f20972292 | |||
| 1b35d4983a | |||
| 452dc77dff | |||
| 1783b11745 | |||
| 74eeae6eee | |||
| 3a7cd3c997 | |||
| b7f6ffa058 | |||
| e1a1e13b5d | |||
| 9cbb87ed25 | |||
| 11bca78f43 | |||
| b6418bc755 | |||
| 122a5085f9 | |||
| cd2b6ab78b | |||
| 9b2804063b | |||
| 7a617346b8 | |||
| 02fa9ed4b9 | |||
| 833991ba34 | |||
| ae65b6f992 | |||
| 88488c112c | |||
| 8313dfccc8 | |||
| e240d6c3f0 | |||
| bbfa81e0c3 |
@@ -13,3 +13,8 @@ Habitica uses [Trello](https://trello.com/b/EpoYEYod/habitica) to track feature
|
||||
# Contributing Code
|
||||
|
||||
See [Contributing to Habitica](http://habitica.fandom.com/wiki/Contributing_to_Habitica#Coders_.28Web_.26_Mobile.29)
|
||||
|
||||
## Issue Triage [](https://www.codetriage.com/habitrpg/habitica)
|
||||
|
||||
You can triage issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to habitrpg on CodeTriage](https://www.codetriage.com/habitrpg/habitica).
|
||||
|
||||
|
||||
@@ -67,12 +67,6 @@
|
||||
"SLACK_FLAGGING_URL": "https://hooks.slack.com/services/id/id/id",
|
||||
"SLACK_SUBSCRIPTIONS_URL": "https://hooks.slack.com/services/id/id/id",
|
||||
"SLACK_URL": "https://hooks.slack.com/services/some-url",
|
||||
"SMTP_HOST": "example.com",
|
||||
"SMTP_PASS": "password",
|
||||
"SMTP_PORT": 587,
|
||||
"SMTP_SERVICE": "Gmail",
|
||||
"SMTP_TLS": "true",
|
||||
"SMTP_USER": "user@example.com",
|
||||
"STRIPE_API_KEY": "aaaabbbbccccddddeeeeffff00001111",
|
||||
"STRIPE_PUB_KEY": "22223333444455556666777788889999",
|
||||
"TEST_DB_URI": "mongodb://localhost/habitrpg_test",
|
||||
|
||||
@@ -13,28 +13,30 @@ const questScrolls = shared.content.quests;
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
let backupUsers;
|
||||
|
||||
async function updateGroup (group) {
|
||||
count++;
|
||||
|
||||
if (group && group.quest && group.quest.leader) {
|
||||
if (group && group.quest && group.quest.key && group.quest.leader) {
|
||||
const quest = questScrolls[group.quest.key];
|
||||
const leader = await User.findOne({_id: group.quest.leader}).exec();
|
||||
|
||||
if (!leader) return;
|
||||
if (leader && quest) {
|
||||
await User.update({
|
||||
_id: leader._id,
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
}, {
|
||||
$set: {migration: MIGRATION_NAME},
|
||||
$inc: {
|
||||
balance: 1,
|
||||
[`items.quests.${group.quest.key}`]: 1,
|
||||
},
|
||||
}).exec();
|
||||
|
||||
await User.update({ _id: leader._id }, {
|
||||
$set: {migration: MIGRATION_NAME},
|
||||
$inc: {
|
||||
balance: 1,
|
||||
[`items.quests.${group.quest.key}`]: 1,
|
||||
},
|
||||
}).exec();
|
||||
|
||||
// unsubscribe from all is already checked by sendTxnEmail
|
||||
if (leader.preferences && leader.preferences.emailNotifications && leader.preferences.emailNotifications.majorUpdates !== false) {
|
||||
sendTxnEmail(leader, 'groups-outage');
|
||||
// unsubscribe from all is already checked by sendTxnEmail
|
||||
if (leader.preferences && leader.preferences.emailNotifications && leader.preferences.emailNotifications.majorUpdates !== false) {
|
||||
sendTxnEmail(leader, 'groups-outage');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +60,7 @@ module.exports = async function processUsers () {
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const groupsPromise = new Promise((resolve, reject) => {
|
||||
backupGroups
|
||||
.find(query, {
|
||||
.find(query, {
|
||||
limit: 250,
|
||||
sort: {_id: 1}
|
||||
})
|
||||
@@ -66,7 +68,7 @@ module.exports = async function processUsers () {
|
||||
resolve(foundGroupInBackup);
|
||||
}).catch(e => {
|
||||
reject(e);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
const groups = await groupsPromise;
|
||||
@@ -77,7 +79,7 @@ module.exports = async function processUsers () {
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: groups[groups.length - 1],
|
||||
$gt: groups[groups.length - 1]._id,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20190731_naming_day';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { model as User } from '../../../website/server/models/user';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
|
||||
let set;
|
||||
let push;
|
||||
const inc = {
|
||||
'items.food.Cake_Base': 1,
|
||||
'items.food.Cake_CottonCandyBlue': 1,
|
||||
'items.food.Cake_CottonCandyPink': 1,
|
||||
'items.food.Cake_Desert': 1,
|
||||
'items.food.Cake_Golden': 1,
|
||||
'items.food.Cake_Red': 1,
|
||||
'items.food.Cake_Shade': 1,
|
||||
'items.food.Cake_Skeleton': 1,
|
||||
'items.food.Cake_White': 1,
|
||||
'items.food.Cake_Zombie': 1,
|
||||
'achievements.habiticaDays': 1,
|
||||
};
|
||||
|
||||
if (user && user.items && user.items.gear && user.items.gear.owned && typeof user.items.gear.owned.body_special_namingDay2018 !== 'undefined') {
|
||||
set = { migration: MIGRATION_NAME };
|
||||
} else if (user && user.items && user.items.gear && user.items.gear.owned && typeof user.items.gear.owned.head_special_namingDay2017 !== 'undefined') {
|
||||
set = { migration: MIGRATION_NAME, 'items.gear.owned.body_special_namingDay2018': false };
|
||||
push = { pinnedItems: { type: 'marketGear', path: 'gear.flat.body_special_namingDay2018', _id: uuid() }};
|
||||
} else if (user && user.items && user.items.pets && typeof user.items.pets['Gryphon-RoyalPurple'] !== 'undefined') {
|
||||
set = { migration: MIGRATION_NAME, 'items.gear.owned.head_special_namingDay2017': false };
|
||||
push = { pinnedItems: { type: 'marketGear', path: 'gear.flat.head_special_namingDay2017', _id: uuid() }};
|
||||
} else if (user && user.items && user.items.mounts && typeof user.items.mounts['Gryphon-RoyalPurple'] !== 'undefined') {
|
||||
set = { migration: MIGRATION_NAME, 'items.pets.Gryphon-RoyalPurple': 5 };
|
||||
} else {
|
||||
set = { migration: MIGRATION_NAME, 'items.mounts.Gryphon-RoyalPurple': true };
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
if (push) {
|
||||
return await User.update({ _id: user._id }, { $set: set, $inc: inc, $push: push }).exec();
|
||||
} else {
|
||||
return await User.update({ _id: user._id }, { $set: set, $inc: inc }).exec();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2019-07-01') },
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1]._id,
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = 'mystery_items_201906';
|
||||
const MYSTERY_ITEMS = ['headAccessory_mystery_201906', 'armor_mystery_201906'];
|
||||
const MIGRATION_NAME = 'mystery_items_201907';
|
||||
const MYSTERY_ITEMS = ['head_mystery_201907', 'armor_mystery_201907', 'eyewear_mystery_201907'];
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
import { model as UserNotification } from '../../website/server/models/userNotification';
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "4.104.1",
|
||||
"version": "4.106.0",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@google-cloud/trace-agent": "^3.6.0",
|
||||
"@google-cloud/trace-agent": "^4.0.0",
|
||||
"@slack/client": "^3.8.1",
|
||||
"accepts": "^1.3.5",
|
||||
"amazon-payments": "^0.2.7",
|
||||
@@ -69,7 +69,6 @@
|
||||
"nconf": "^0.10.0",
|
||||
"node-gcm": "^1.0.2",
|
||||
"node-sass": "^4.9.0",
|
||||
"nodemailer": "^6.0.0",
|
||||
"ora": "^3.2.0",
|
||||
"pageres": "^5.1.0",
|
||||
"passport": "^0.4.0",
|
||||
@@ -89,7 +88,7 @@
|
||||
"stripe": "^5.9.0",
|
||||
"superagent": "^5.0.2",
|
||||
"svg-inline-loader": "^0.8.0",
|
||||
"svg-url-loader": "^2.3.2",
|
||||
"svg-url-loader": "^3.0.0",
|
||||
"svgo": "^1.2.0",
|
||||
"svgo-loader": "^2.1.0",
|
||||
"universal-analytics": "^0.4.17",
|
||||
@@ -152,7 +151,7 @@
|
||||
"chai": "^4.1.2",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chalk": "^2.4.1",
|
||||
"chromedriver": "^73.0.0",
|
||||
"chromedriver": "^76.0.0",
|
||||
"connect-history-api-fallback": "^1.1.0",
|
||||
"coveralls": "^3.0.3",
|
||||
"cross-spawn": "^6.0.5",
|
||||
|
||||
@@ -58,7 +58,7 @@ async function _deleteHabiticaData (user, email) {
|
||||
}
|
||||
|
||||
async function _processEmailAddress (email) {
|
||||
const emailRegex = new RegExp(`^${email}`, 'i');
|
||||
const emailRegex = new RegExp(`^${email}$`, 'i');
|
||||
const users = await User.find({
|
||||
$or: [
|
||||
{'auth.local.email': emailRegex},
|
||||
|
||||
@@ -1232,7 +1232,7 @@ describe('cron', () => {
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.history.exp).to.have.lengthOf(1);
|
||||
expect(user.history.exp[0].value).to.equal(150);
|
||||
expect(user.history.exp[0].value).to.equal(25);
|
||||
});
|
||||
|
||||
it('increments perfect day achievement if all (at least 1) due dailies were completed', () => {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/* eslint-disable global-require */
|
||||
import got from 'got';
|
||||
import nconf from 'nconf';
|
||||
import nodemailer from 'nodemailer';
|
||||
import requireAgain from 'require-again';
|
||||
import logger from '../../../../website/server/libs/logger';
|
||||
import { TAVERN_ID } from '../../../../website/server/models/group';
|
||||
import { defer } from '../../../helpers/api-unit.helper';
|
||||
|
||||
@@ -35,42 +33,6 @@ function getUser () {
|
||||
describe('emails', () => {
|
||||
let pathToEmailLib = '../../../../website/server/libs/email';
|
||||
|
||||
describe('sendEmail', () => {
|
||||
let sendMailSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
sendMailSpy = sandbox.stub().returns(defer().promise);
|
||||
sandbox.stub(nodemailer, 'createTransport').returns({
|
||||
sendMail: sendMailSpy,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('can send an email using the default transport', () => {
|
||||
let attachEmail = requireAgain(pathToEmailLib);
|
||||
attachEmail.send();
|
||||
expect(sendMailSpy).to.be.calledOnce;
|
||||
});
|
||||
|
||||
it('logs errors', (done) => {
|
||||
sandbox.stub(logger, 'error');
|
||||
|
||||
let attachEmail = requireAgain(pathToEmailLib);
|
||||
attachEmail.send();
|
||||
expect(sendMailSpy).to.be.calledOnce;
|
||||
defer().reject();
|
||||
|
||||
// wait for unhandledRejection event to fire
|
||||
setTimeout(() => {
|
||||
expect(logger.error).to.be.calledOnce;
|
||||
done();
|
||||
}, 20);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUserInfo', () => {
|
||||
it('returns an empty object if no field request', () => {
|
||||
let attachEmail = requireAgain(pathToEmailLib);
|
||||
@@ -84,7 +46,7 @@ describe('emails', () => {
|
||||
let user = getUser();
|
||||
let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
|
||||
expect(data).to.have.property('name', user.profile.name);
|
||||
expect(data).to.have.property('name', user.auth.local.username);
|
||||
expect(data).to.have.property('email', user.auth.local.email);
|
||||
expect(data).to.have.property('_id', user._id);
|
||||
expect(data).to.have.property('canSend', true);
|
||||
@@ -95,11 +57,11 @@ describe('emails', () => {
|
||||
let getUserInfo = attachEmail.getUserInfo;
|
||||
let user = getUser();
|
||||
delete user.profile.name;
|
||||
delete user.auth.local;
|
||||
delete user.auth.local.email;
|
||||
|
||||
let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
|
||||
expect(data).to.have.property('name', user.profile.name);
|
||||
expect(data).to.have.property('name', user.auth.local.username);
|
||||
expect(data).to.have.property('email', user.auth.facebook.emails[0].value);
|
||||
expect(data).to.have.property('_id', user._id);
|
||||
expect(data).to.have.property('canSend', true);
|
||||
@@ -114,7 +76,7 @@ describe('emails', () => {
|
||||
|
||||
let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
|
||||
|
||||
expect(data).to.have.property('name', user.profile.name);
|
||||
expect(data).to.have.property('name', user.auth.local.username);
|
||||
expect(data).not.to.have.property('email');
|
||||
expect(data).to.have.property('_id', user._id);
|
||||
expect(data).to.have.property('canSend', true);
|
||||
|
||||
@@ -16,6 +16,7 @@ describe('payments/index', () => {
|
||||
beforeEach(async () => {
|
||||
user = new User();
|
||||
user.profile.name = 'sender';
|
||||
user.auth.local.username = 'sender';
|
||||
await user.save();
|
||||
|
||||
group = generateGroup({
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
SPAM_MIN_EXEMPT_CONTRIB_LEVEL,
|
||||
TAVERN_ID,
|
||||
} from '../../../../../website/server/models/group';
|
||||
import { CHAT_FLAG_FROM_SHADOW_MUTE } from '../../../../../website/common/script/constants';
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
import { getMatchesByWordArray } from '../../../../../website/server/libs/stringUtils';
|
||||
import bannedWords from '../../../../../website/server/libs/bannedWords';
|
||||
@@ -81,6 +82,10 @@ describe('POST /chat', () => {
|
||||
});
|
||||
|
||||
describe('mute user', () => {
|
||||
afterEach(() => {
|
||||
member.update({'flags.chatRevoked': false});
|
||||
});
|
||||
|
||||
it('returns an error when chat privileges are revoked when sending a message to a public guild', async () => {
|
||||
const userWithChatRevoked = await member.update({'flags.chatRevoked': true});
|
||||
await expect(userWithChatRevoked.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage})).to.eventually.be.rejected.and.eql({
|
||||
@@ -89,6 +94,129 @@ describe('POST /chat', () => {
|
||||
message: t('chatPrivilegesRevoked'),
|
||||
});
|
||||
});
|
||||
|
||||
it('does not error when chat privileges are revoked when sending a message to a private guild', async () => {
|
||||
const { group, members } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'Private Guild',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
|
||||
const privateGuildMemberWithChatsRevoked = members[0];
|
||||
await privateGuildMemberWithChatsRevoked.update({'flags.chatRevoked': true});
|
||||
|
||||
const message = await privateGuildMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage});
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
});
|
||||
|
||||
it('does not error when chat privileges are revoked when sending a message to a party', async () => {
|
||||
const { group, members } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'Party',
|
||||
type: 'party',
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
|
||||
const privatePartyMemberWithChatsRevoked = members[0];
|
||||
await privatePartyMemberWithChatsRevoked.update({'flags.chatRevoked': true});
|
||||
|
||||
const message = await privatePartyMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage});
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
describe('shadow-mute user', () => {
|
||||
beforeEach(() => {
|
||||
sandbox.spy(email, 'sendTxn');
|
||||
sandbox.stub(IncomingWebhook.prototype, 'send');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
member.update({'flags.chatShadowMuted': false});
|
||||
});
|
||||
|
||||
it('creates a chat with flagCount already set and notifies mods when sending a message to a public guild', async () => {
|
||||
const userWithChatShadowMuted = await member.update({'flags.chatShadowMuted': true});
|
||||
const message = await userWithChatShadowMuted.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage});
|
||||
expect(message.message.id).to.exist;
|
||||
expect(message.message.flagCount).to.eql(CHAT_FLAG_FROM_SHADOW_MUTE);
|
||||
|
||||
// Email sent to mods
|
||||
await sleep(0.5);
|
||||
expect(email.sendTxn).to.be.calledOnce;
|
||||
expect(email.sendTxn.args[0][1]).to.eql('shadow-muted-post-report-to-mods');
|
||||
|
||||
// Slack message to mods
|
||||
expect(IncomingWebhook.prototype.send).to.be.calledOnce;
|
||||
/* eslint-disable camelcase */
|
||||
expect(IncomingWebhook.prototype.send).to.be.calledWith({
|
||||
text: `@${member.auth.local.username} / ${member.profile.name} posted while shadow-muted`,
|
||||
attachments: [{
|
||||
fallback: 'Shadow-Muted Message',
|
||||
color: 'danger',
|
||||
author_name: `@${member.auth.local.username} ${member.profile.name} (${member.auth.local.email}; ${member._id})`,
|
||||
title: 'Shadow-Muted Post in Test Guild',
|
||||
title_link: `${BASE_URL}/groups/guild/${groupWithChat.id}`,
|
||||
text: testMessage,
|
||||
mrkdwn_in: [
|
||||
'text',
|
||||
],
|
||||
}],
|
||||
});
|
||||
/* eslint-enable camelcase */
|
||||
});
|
||||
|
||||
it('creates a chat with zero flagCount when sending a message to a private guild', async () => {
|
||||
const { group, members } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'Private Guild',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
|
||||
const userWithChatShadowMuted = members[0];
|
||||
await userWithChatShadowMuted.update({'flags.chatShadowMuted': true});
|
||||
|
||||
const message = await userWithChatShadowMuted.post(`/groups/${group._id}/chat`, { message: testMessage});
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
expect(message.message.flagCount).to.eql(0);
|
||||
});
|
||||
|
||||
it('creates a chat with zero flagCount when sending a message to a party', async () => {
|
||||
const { group, members } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'Party',
|
||||
type: 'party',
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
|
||||
const userWithChatShadowMuted = members[0];
|
||||
await userWithChatShadowMuted.update({'flags.chatShadowMuted': true});
|
||||
|
||||
const message = await userWithChatShadowMuted.post(`/groups/${group._id}/chat`, { message: testMessage});
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
expect(message.message.flagCount).to.eql(0);
|
||||
});
|
||||
|
||||
it('creates a chat with zero flagCount when non-shadow-muted user sends a message to a public guild', async () => {
|
||||
const message = await member.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage});
|
||||
expect(message.message.id).to.exist;
|
||||
expect(message.message.flagCount).to.eql(0);
|
||||
});
|
||||
});
|
||||
|
||||
context('banned word', () => {
|
||||
@@ -235,6 +363,7 @@ describe('POST /chat', () => {
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
user.update({'flags.chatRevoked': false});
|
||||
});
|
||||
|
||||
it('errors and revokes privileges when chat message contains a banned slur', async () => {
|
||||
@@ -274,11 +403,6 @@ describe('POST /chat', () => {
|
||||
error: 'NotAuthorized',
|
||||
message: t('chatPrivilegesRevoked'),
|
||||
});
|
||||
|
||||
// @TODO: The next test should not depend on this. We should reset the user test in a beforeEach
|
||||
// Restore chat privileges to continue testing
|
||||
user.flags.chatRevoked = false;
|
||||
await user.update({'flags.chatRevoked': false});
|
||||
});
|
||||
|
||||
it('does not allow slurs in private groups', async () => {
|
||||
@@ -327,10 +451,6 @@ describe('POST /chat', () => {
|
||||
error: 'NotAuthorized',
|
||||
message: t('chatPrivilegesRevoked'),
|
||||
});
|
||||
|
||||
// Restore chat privileges to continue testing
|
||||
members[0].flags.chatRevoked = false;
|
||||
await members[0].update({'flags.chatRevoked': false});
|
||||
});
|
||||
|
||||
it('errors when slur is typed in mixed case', async () => {
|
||||
@@ -345,42 +465,6 @@ describe('POST /chat', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('does not error when sending a message to a private guild with a user with revoked chat', async () => {
|
||||
let { group, members } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'Private Guild',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
|
||||
let privateGuildMemberWithChatsRevoked = members[0];
|
||||
await privateGuildMemberWithChatsRevoked.update({'flags.chatRevoked': true});
|
||||
|
||||
let message = await privateGuildMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage});
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
});
|
||||
|
||||
it('does not error when sending a message to a party with a user with revoked chat', async () => {
|
||||
let { group, members } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'Party',
|
||||
type: 'party',
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
|
||||
let privatePartyMemberWithChatsRevoked = members[0];
|
||||
await privatePartyMemberWithChatsRevoked.update({'flags.chatRevoked': true});
|
||||
|
||||
let message = await privatePartyMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage});
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
});
|
||||
|
||||
it('creates a chat', async () => {
|
||||
const newMessage = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage});
|
||||
const groupMessages = await user.get(`/groups/${groupWithChat._id}/chat`);
|
||||
@@ -486,35 +570,55 @@ describe('POST /chat', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('notifies other users of new messages for a guild', async () => {
|
||||
let message = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage});
|
||||
let memberWithNotification = await member.get('/user');
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
expect(memberWithNotification.newMessages[`${groupWithChat._id}`]).to.exist;
|
||||
expect(memberWithNotification.notifications.find(n => {
|
||||
return n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupWithChat._id;
|
||||
})).to.exist;
|
||||
});
|
||||
|
||||
it('notifies other users of new messages for a party', async () => {
|
||||
let { group, groupLeader, members } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'Test Party',
|
||||
type: 'party',
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 1,
|
||||
context('chat notifications', () => {
|
||||
beforeEach(() => {
|
||||
member.update({newMessages: {}, notifications: []});
|
||||
});
|
||||
|
||||
let message = await groupLeader.post(`/groups/${group._id}/chat`, { message: testMessage});
|
||||
let memberWithNotification = await members[0].get('/user');
|
||||
it('notifies other users of new messages for a guild', async () => {
|
||||
let message = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
|
||||
let memberWithNotification = await member.get('/user');
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
expect(memberWithNotification.newMessages[`${group._id}`]).to.exist;
|
||||
expect(memberWithNotification.notifications.find(n => {
|
||||
return n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === group._id;
|
||||
})).to.exist;
|
||||
expect(message.message.id).to.exist;
|
||||
expect(memberWithNotification.newMessages[`${groupWithChat._id}`]).to.exist;
|
||||
expect(memberWithNotification.notifications.find(n => {
|
||||
return n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupWithChat._id;
|
||||
})).to.exist;
|
||||
});
|
||||
|
||||
it('notifies other users of new messages for a party', async () => {
|
||||
let { group, groupLeader, members } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'Test Party',
|
||||
type: 'party',
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
|
||||
let message = await groupLeader.post(`/groups/${group._id}/chat`, { message: testMessage });
|
||||
let memberWithNotification = await members[0].get('/user');
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
expect(memberWithNotification.newMessages[`${group._id}`]).to.exist;
|
||||
expect(memberWithNotification.notifications.find(n => {
|
||||
return n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === group._id;
|
||||
})).to.exist;
|
||||
});
|
||||
|
||||
it('does not notify other users of a new message that is already hidden from shadow-muting', async () => {
|
||||
await user.update({'flags.chatShadowMuted': true});
|
||||
let message = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
|
||||
let memberWithNotification = await member.get('/user');
|
||||
|
||||
await user.update({'flags.chatShadowMuted': false});
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
expect(memberWithNotification.newMessages[`${groupWithChat._id}`]).to.not.exist;
|
||||
expect(memberWithNotification.notifications.find(n => {
|
||||
return n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupWithChat._id;
|
||||
})).to.not.exist;
|
||||
});
|
||||
});
|
||||
|
||||
context('Spam prevention', () => {
|
||||
@@ -533,7 +637,7 @@ describe('POST /chat', () => {
|
||||
});
|
||||
|
||||
it('contributor should not receive spam alert', async () => {
|
||||
let userSocialite = await member.update({'contributor.level': SPAM_MIN_EXEMPT_CONTRIB_LEVEL, 'flags.chatRevoked': false});
|
||||
let userSocialite = await member.update({'contributor.level': SPAM_MIN_EXEMPT_CONTRIB_LEVEL});
|
||||
|
||||
// Post 1 more message than the spam limit to ensure they do not reach the limit
|
||||
for (let i = 0; i < SPAM_MESSAGE_LIMIT + 1; i++) {
|
||||
|
||||
@@ -105,16 +105,22 @@ describe('PUT /heroes/:heroId', () => {
|
||||
|
||||
it('updates chatRevoked flag', async () => {
|
||||
let hero = await generateUser();
|
||||
|
||||
await user.put(`/hall/heroes/${hero._id}`, {
|
||||
flags: {chatRevoked: true},
|
||||
});
|
||||
|
||||
await hero.sync();
|
||||
|
||||
expect(hero.flags.chatRevoked).to.eql(true);
|
||||
});
|
||||
|
||||
it('updates chatShadowMuted flag', async () => {
|
||||
let hero = await generateUser();
|
||||
await user.put(`/hall/heroes/${hero._id}`, {
|
||||
flags: {chatShadowMuted: true},
|
||||
});
|
||||
await hero.sync();
|
||||
expect(hero.flags.chatShadowMuted).to.eql(true);
|
||||
});
|
||||
|
||||
it('updates contributor level', async () => {
|
||||
let hero = await generateUser({
|
||||
contributor: {level: 5},
|
||||
|
||||
@@ -6,7 +6,7 @@ describe('GET /inbox/messages', () => {
|
||||
let user;
|
||||
let otherUser;
|
||||
|
||||
before(async () => {
|
||||
beforeEach(async () => {
|
||||
[user, otherUser] = await Promise.all([generateUser(), generateUser()]);
|
||||
|
||||
await otherUser.post('/members/send-private-message', {
|
||||
|
||||
@@ -54,6 +54,21 @@ describe('POST /tasks/challenge/:challengeId', () => {
|
||||
expect(tasksOrder.habits).to.include(task.id);
|
||||
});
|
||||
|
||||
it('allows non-leader admin to add tasks to a challenge when not a member', async () => {
|
||||
const admin = await generateUser({'contributor.admin': true});
|
||||
let task = await admin.post(`/tasks/challenge/${challenge._id}`, {
|
||||
text: 'test habit from admin',
|
||||
type: 'habit',
|
||||
up: false,
|
||||
down: true,
|
||||
notes: 1976,
|
||||
});
|
||||
|
||||
let {tasksOrder} = await user.get(`/challenges/${challenge._id}`);
|
||||
|
||||
expect(tasksOrder.habits).to.include(task.id);
|
||||
});
|
||||
|
||||
it('returns error when user tries to create task with a alias', async () => {
|
||||
await expect(user.post(`/tasks/challenge/${challenge._id}`, {
|
||||
text: 'test habit',
|
||||
|
||||
@@ -44,7 +44,7 @@ describe('DELETE /inbox/messages/:messageId', () => {
|
||||
});
|
||||
|
||||
it('deletes one message', async () => {
|
||||
const messages = await user.get('/inbox/messages');
|
||||
const messages = await user.get('/inbox/paged-messages');
|
||||
|
||||
expect(messages.length).to.equal(3);
|
||||
|
||||
@@ -53,10 +53,10 @@ describe('DELETE /inbox/messages/:messageId', () => {
|
||||
expect(messages[2].text).to.equal('first');
|
||||
|
||||
await user.del(`/inbox/messages/${messages[1]._id}`);
|
||||
const updatedMessages = await user.get('/inbox/messages');
|
||||
const updatedMessages = await user.get('/inbox/paged-messages');
|
||||
expect(updatedMessages.length).to.equal(2);
|
||||
|
||||
expect(updatedMessages[0].text).to.equal('third');
|
||||
expect(updatedMessages[1].text).to.equal('first');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ describe('GET /inbox/conversations', () => {
|
||||
let otherUser;
|
||||
let thirdUser;
|
||||
|
||||
before(async () => {
|
||||
beforeEach(async () => {
|
||||
[user, otherUser, thirdUser] = await Promise.all([generateUser(), generateUser(), generateUser()]);
|
||||
|
||||
await otherUser.post('/members/send-private-message', {
|
||||
@@ -41,4 +41,51 @@ describe('GET /inbox/conversations', () => {
|
||||
expect(result[0].user).to.be.equal(user.profile.name);
|
||||
expect(result[0].username).to.be.equal(user.auth.local.username);
|
||||
});
|
||||
|
||||
it('returns the user inbox messages as an array of ordered messages (from most to least recent)', async () => {
|
||||
const messages = await user.get('/inbox/paged-messages');
|
||||
|
||||
expect(messages.length).to.equal(5);
|
||||
|
||||
// message to yourself
|
||||
expect(messages[0].text).to.equal('fifth');
|
||||
expect(messages[0].sent).to.equal(false);
|
||||
expect(messages[0].uuid).to.equal(user._id);
|
||||
|
||||
expect(messages[1].text).to.equal('fourth');
|
||||
expect(messages[2].text).to.equal('third');
|
||||
expect(messages[3].text).to.equal('second');
|
||||
expect(messages[4].text).to.equal('first');
|
||||
});
|
||||
|
||||
it('returns four messages when using page-query ', async () => {
|
||||
const promises = [];
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
promises.push(user.post('/members/send-private-message', {
|
||||
toUserId: user.id,
|
||||
message: 'fourth',
|
||||
}));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
const messages = await user.get('/inbox/paged-messages?page=1');
|
||||
|
||||
expect(messages.length).to.equal(5);
|
||||
});
|
||||
|
||||
it('returns only the messages of one conversation', async () => {
|
||||
const messages = await user.get(`/inbox/paged-messages?conversation=${otherUser.id}`);
|
||||
|
||||
expect(messages.length).to.equal(3);
|
||||
});
|
||||
|
||||
it('returns the correct message format', async () => {
|
||||
const messages = await otherUser.get(`/inbox/paged-messages?conversation=${user.id}`);
|
||||
|
||||
expect(messages[0].toUUID).to.equal(user.id); // from user
|
||||
expect(messages[1].toUUID).to.not.exist; // only filled if its from the chat partner
|
||||
expect(messages[2].toUUID).to.equal(user.id); // from user
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,10 +19,10 @@ describe('POST /members/flag-private-message/:messageId', () => {
|
||||
toUserId: receiver._id,
|
||||
});
|
||||
|
||||
let senderMessages = await userToSendMessage.get('/inbox/messages');
|
||||
let senderMessages = await userToSendMessage.get('/inbox/paged-messages');
|
||||
|
||||
let sendersMessageInSendersInbox = _.find(senderMessages, (message) => {
|
||||
return message.uuid === receiver._id && message.text === messageToSend;
|
||||
return message.toUUID === receiver._id && message.text === messageToSend;
|
||||
});
|
||||
|
||||
expect(sendersMessageInSendersInbox).to.exist;
|
||||
@@ -37,7 +37,7 @@ describe('POST /members/flag-private-message/:messageId', () => {
|
||||
toUserId: receiver._id,
|
||||
});
|
||||
|
||||
let receiversMessages = await receiver.get('/inbox/messages');
|
||||
let receiversMessages = await receiver.get('/inbox/paged-messages');
|
||||
|
||||
let sendersMessageInReceiversInbox = _.find(receiversMessages, (message) => {
|
||||
return message.uuid === userToSendMessage._id && message.text === messageToSend;
|
||||
@@ -55,7 +55,7 @@ describe('POST /members/flag-private-message/:messageId', () => {
|
||||
toUserId: receiver._id,
|
||||
});
|
||||
|
||||
let receiversMessages = await receiver.get('/inbox/messages');
|
||||
let receiversMessages = await receiver.get('/inbox/paged-messages');
|
||||
|
||||
let sendersMessageInReceiversInbox = _.find(receiversMessages, (message) => {
|
||||
return message.uuid === userToSendMessage._id && message.text === messageToSend;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import ChallengeDetailComponent from 'client/components/challenges/challengeDetail.vue';
|
||||
import Store from 'client/libs/store';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Store);
|
||||
|
||||
describe('Challenge Detail', () => {
|
||||
let store;
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
store = new Store({
|
||||
state: {
|
||||
user: {
|
||||
data: {
|
||||
contributor: {
|
||||
admin: false,
|
||||
},
|
||||
challenges: [],
|
||||
stats: {
|
||||
},
|
||||
flags: {},
|
||||
preferences: {},
|
||||
party: {
|
||||
quest: {
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
'members:getChallengeMembers': () => {},
|
||||
'challenges:getChallenge': () => [
|
||||
{_id: '1', group: { name: '', type: ''}, memberCount: 1, name: '', summary: '', description: '', leader: '', price: 1},
|
||||
],
|
||||
'tasks:getChallengeTasks': () => [
|
||||
{_id: '1', type: 'habit'},
|
||||
{_id: '2', type: 'daily'},
|
||||
{_id: '3', type: 'reward'},
|
||||
{_id: '4', type: 'todo'},
|
||||
],
|
||||
},
|
||||
getters: {
|
||||
},
|
||||
});
|
||||
wrapper = shallowMount(ChallengeDetailComponent, {
|
||||
store,
|
||||
localVue,
|
||||
mocks: {
|
||||
$t: (string) => string,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('removes a destroyed task from task list', () => {
|
||||
let taskToRemove = {_id: '1', type: 'habit'};
|
||||
wrapper.vm.taskDestroyed(taskToRemove);
|
||||
expect(wrapper.vm.tasksByType[taskToRemove.type].length).to.eq(0);
|
||||
});
|
||||
});
|
||||
@@ -86,7 +86,7 @@ export async function generateGroup (leader, details = {}, update = {}) {
|
||||
// This is generate group + the ability to create
|
||||
// real users to populate it. The settings object
|
||||
// takes in:
|
||||
// members: Number - the number of group members to create. Defaults to 0.
|
||||
// members: Number - the number of group members to create. Defaults to 0. Does not include group leader.
|
||||
// inivtes: Number - the number of users to create and invite to the group. Defaults to 0.
|
||||
// groupDetails: Object - how to initialize the group
|
||||
// leaderDetails: Object - defaults for the leader, defaults with a gem balance so the user
|
||||
|
||||
@@ -80,7 +80,7 @@ export async function generateGroup (leader, details = {}, update = {}) {
|
||||
// This is generate group + the ability to create
|
||||
// real users to populate it. The settings object
|
||||
// takes in:
|
||||
// members: Number - the number of group members to create. Defaults to 0.
|
||||
// members: Number - the number of group members to create. Defaults to 0. Does not include group leader.
|
||||
// inivtes: Number - the number of users to create and invite to the group. Defaults to 0.
|
||||
// groupDetails: Object - how to initialize the group
|
||||
// leaderDetails: Object - defaults for the leader, defaults with a gem balance so the user
|
||||
|
||||
@@ -57,6 +57,7 @@ div
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#loading-screen-inapp {
|
||||
@@ -89,7 +90,6 @@ div
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
overflow-x: hidden;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,78 +1,36 @@
|
||||
.promo_armoire_backgrounds_201907 {
|
||||
.promo_armoire_backgrounds_201908 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -313px -524px;
|
||||
background-position: 0px 0px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_glass_watery_potions {
|
||||
.promo_mystery_201907 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -854px 0px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_mystery_201906 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -854px -296px;
|
||||
background-position: -424px 0px;
|
||||
width: 282px;
|
||||
height: 147px;
|
||||
height: 144px;
|
||||
}
|
||||
.promo_orcas {
|
||||
.promo_naming_day_2018 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -854px -444px;
|
||||
width: 219px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_seafoam {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -376px -337px;
|
||||
width: 425px;
|
||||
height: 148px;
|
||||
}
|
||||
.promo_seasonal_shop {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1074px -444px;
|
||||
width: 162px;
|
||||
height: 132px;
|
||||
}
|
||||
.promo_splashy_pals_bundle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -854px -148px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_splashy_skins {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -337px;
|
||||
width: 375px;
|
||||
height: 186px;
|
||||
}
|
||||
.customize-option.promo_splashy_skins {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -25px -352px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.promo_summer_splash_2019 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -445px 0px;
|
||||
width: 408px;
|
||||
height: 186px;
|
||||
background-position: 0px -148px;
|
||||
width: 285px;
|
||||
height: 162px;
|
||||
}
|
||||
.promo_take_this {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1137px -296px;
|
||||
background-position: -596px -145px;
|
||||
width: 96px;
|
||||
height: 69px;
|
||||
}
|
||||
.scene_casting_spells {
|
||||
.scene_reading {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -524px;
|
||||
width: 312px;
|
||||
height: 222px;
|
||||
background-position: -424px -145px;
|
||||
width: 171px;
|
||||
height: 144px;
|
||||
}
|
||||
.scene_hat_guild {
|
||||
.scene_rewards {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px 0px;
|
||||
width: 444px;
|
||||
height: 336px;
|
||||
background-position: 0px -311px;
|
||||
width: 207px;
|
||||
height: 180px;
|
||||
}
|
||||
|
||||
@@ -364,769 +364,769 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_among_giant_anemones {
|
||||
.background_amid_ancient_ruins {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1136px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_apple_picking {
|
||||
.background_among_giant_anemones {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1136px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_aquarium {
|
||||
.background_apple_picking {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -1036px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_archaeological_dig {
|
||||
.background_aquarium {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -1036px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_archery_range {
|
||||
.background_archaeological_dig {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -1036px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_at_the_docks {
|
||||
.background_archery_range {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -1036px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_aurora {
|
||||
.background_at_the_docks {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -1036px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_autumn_forest {
|
||||
.background_aurora {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -1036px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_avalanche {
|
||||
.background_autumn_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -1036px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_back_alley {
|
||||
.background_avalanche {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -1036px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_back_of_giant_beast {
|
||||
.background_back_alley {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1136px -1036px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_bamboo_forest {
|
||||
.background_back_of_giant_beast {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1278px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_bayou {
|
||||
.background_bamboo_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1278px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_beach {
|
||||
.background_bayou {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1278px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_beehive {
|
||||
.background_beach {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1278px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_bell_tower {
|
||||
.background_beehive {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1278px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_beside_well {
|
||||
.background_bell_tower {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1278px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_birch_forest {
|
||||
.background_beside_well {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1278px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_blacksmithy {
|
||||
.background_birch_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1278px -1036px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_blizzard {
|
||||
.background_blacksmithy {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -1184px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_blossoming_desert {
|
||||
.background_blizzard {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -1184px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_blue {
|
||||
.background_blossoming_desert {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -1184px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_bridge {
|
||||
.background_blue {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -1184px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_bug_covered_log {
|
||||
.background_bridge {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -1184px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_buried_treasure {
|
||||
.background_bug_covered_log {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -1184px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_champions_colosseum {
|
||||
.background_buried_treasure {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -1184px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_cherry_trees {
|
||||
.background_champions_colosseum {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -1184px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_chessboard_land {
|
||||
.background_cherry_trees {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1136px -1184px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_clouds {
|
||||
.background_chessboard_land {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1278px -1184px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_coral_reef {
|
||||
.background_clouds {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1420px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_cornfields {
|
||||
.background_coral_reef {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1420px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_cozy_barn {
|
||||
.background_cornfields {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1420px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_cozy_bedroom {
|
||||
.background_cozy_barn {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_cozy_library {
|
||||
.background_cozy_bedroom {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1420px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_creepy_castle {
|
||||
.background_cozy_library {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1420px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_crosscountry_ski_trail {
|
||||
.background_creepy_castle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1420px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_crystal_cave {
|
||||
.background_crosscountry_ski_trail {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1420px -1036px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dark_deep {
|
||||
.background_crystal_cave {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1420px -1184px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_deep_mine {
|
||||
.background_dark_deep {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -1332px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_deep_sea {
|
||||
.background_deep_mine {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -1332px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_desert_dunes {
|
||||
.background_deep_sea {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -1332px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dilatory_castle {
|
||||
.background_desert_dunes {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -1332px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dilatory_city {
|
||||
.background_dilatory_castle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -1332px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dilatory_ruins {
|
||||
.background_dilatory_city {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -1332px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_distant_castle {
|
||||
.background_dilatory_ruins {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -1332px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dojo {
|
||||
.background_distant_castle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -1332px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_drifting_raft {
|
||||
.background_dojo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1136px -1332px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_driving_a_coach {
|
||||
.background_drifting_raft {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1278px -1332px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_driving_a_sleigh {
|
||||
.background_driving_a_coach {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1420px -1332px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_duck_pond {
|
||||
.background_driving_a_sleigh {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1562px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dungeon {
|
||||
.background_duck_pond {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1562px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dusty_canyons {
|
||||
.background_dungeon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1562px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_elegant_balcony {
|
||||
.background_dusty_canyons {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1562px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_fairy_ring {
|
||||
.background_elegant_balcony {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1562px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_fantastical_shoe_store {
|
||||
.background_fairy_ring {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1562px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_farmhouse {
|
||||
.background_fantastical_shoe_store {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1562px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_fiber_arts_room {
|
||||
.background_farmhouse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1562px -1036px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_field_with_colored_eggs {
|
||||
.background_fiber_arts_room {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1562px -1184px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_floating_islands {
|
||||
.background_field_with_colored_eggs {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1562px -1332px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_floral_meadow {
|
||||
.background_floating_islands {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -1480px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_flower_market {
|
||||
.background_floral_meadow {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -1480px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.customize-option.background_flower_market {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -167px -1495px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.background_flying_over_a_field_of_wildflowers {
|
||||
.background_flower_market {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -1480px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.customize-option.background_flying_over_a_field_of_wildflowers {
|
||||
.customize-option.background_flower_market {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -309px -1495px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.background_flying_over_an_ancient_forest {
|
||||
.background_flying_over_a_field_of_wildflowers {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -1480px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_flying_over_icy_steppes {
|
||||
.customize-option.background_flying_over_a_field_of_wildflowers {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -451px -1495px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.background_flying_over_an_ancient_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -1480px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_flying_over_rocky_canyon {
|
||||
.background_flying_over_icy_steppes {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -1480px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_flying_over_snowy_mountains {
|
||||
.background_flying_over_rocky_canyon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -1480px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_flying_over_tropical_islands {
|
||||
.background_flying_over_snowy_mountains {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1420px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_forest {
|
||||
.background_flying_over_tropical_islands {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1136px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_frigid_peak {
|
||||
.background_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1136px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_frosty_forest {
|
||||
.background_frigid_peak {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1136px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_frozen_lake {
|
||||
.background_frosty_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1136px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_garden_shed {
|
||||
.background_frozen_lake {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_gazebo {
|
||||
.background_garden_shed {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_birdhouse {
|
||||
.background_gazebo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_book {
|
||||
.background_giant_birdhouse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_florals {
|
||||
.background_giant_book {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_seashell {
|
||||
.background_giant_dandelions {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_wave {
|
||||
.background_giant_florals {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_glowing_mushroom_cave {
|
||||
.background_giant_seashell {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_gorgeous_greenhouse {
|
||||
.background_giant_wave {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_grand_staircase {
|
||||
.background_glowing_mushroom_cave {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_graveyard {
|
||||
.background_gorgeous_greenhouse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_green {
|
||||
.background_grand_staircase {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_guardian_statues {
|
||||
.background_graveyard {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_gumdrop_land {
|
||||
.background_green {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_habit_city_streets {
|
||||
.background_guardian_statues {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_halflings_house {
|
||||
.background_gumdrop_land {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_harvest_feast {
|
||||
.background_habit_city_streets {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_harvest_fields {
|
||||
.background_halflings_house {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_harvest_moon {
|
||||
.background_harvest_feast {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_haunted_house {
|
||||
.background_harvest_fields {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_ice_cave {
|
||||
.background_harvest_moon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_iceberg {
|
||||
.background_haunted_house {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_idyllic_cabin {
|
||||
.background_ice_cave {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_island_waterfalls {
|
||||
.background_iceberg {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_kelp_forest {
|
||||
.background_idyllic_cabin {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_lake_with_floating_lanterns {
|
||||
.background_island_waterfalls {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_lighthouse_shore {
|
||||
.background_kelp_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_lilypad {
|
||||
.background_lake_with_floating_lanterns {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_magic_beanstalk {
|
||||
.background_lighthouse_shore {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_magical_candles {
|
||||
.background_lilypad {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_magical_museum {
|
||||
.background_magic_beanstalk {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_marble_temple {
|
||||
.background_magical_candles {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_market {
|
||||
.background_magical_museum {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_meandering_cave {
|
||||
.background_marble_temple {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_medieval_kitchen {
|
||||
.background_market {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_midnight_castle {
|
||||
.background_meandering_cave {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_midnight_clouds {
|
||||
.background_medieval_kitchen {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_midnight_lake {
|
||||
.background_midnight_castle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_mist_shrouded_mountain {
|
||||
.background_midnight_clouds {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_mistiflying_circus {
|
||||
.background_midnight_lake {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_mountain_lake {
|
||||
.background_mist_shrouded_mountain {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_mountain_pyramid {
|
||||
.background_mistiflying_circus {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_night_dunes {
|
||||
.background_mountain_lake {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_ocean_sunrise {
|
||||
.background_mountain_pyramid {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_old_fashioned_bakery {
|
||||
.background_night_dunes {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_on_tree_branch {
|
||||
.background_ocean_sunrise {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_open_waters {
|
||||
.background_old_fashioned_bakery {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_orchard {
|
||||
.background_on_tree_branch {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_pagodas {
|
||||
.background_open_waters {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_park_with_statue {
|
||||
.background_orchard {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_pirate_flag {
|
||||
.background_pagodas {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_pixelists_workshop {
|
||||
.background_park_with_statue {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_pumpkin_patch {
|
||||
.background_pirate_flag {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_purple {
|
||||
.background_pixelists_workshop {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_pyramids {
|
||||
.background_pumpkin_patch {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px 0px;
|
||||
width: 141px;
|
||||
|
||||
@@ -4,69 +4,99 @@
|
||||
width: 221px;
|
||||
height: 39px;
|
||||
}
|
||||
.quest_dolphin {
|
||||
.quest_dilatory {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -443px 0px;
|
||||
background-position: -1320px -660px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_dustbunnies {
|
||||
.quest_dilatoryDistress1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1323px -660px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
background-position: -1540px -1085px;
|
||||
width: 210px;
|
||||
height: 210px;
|
||||
}
|
||||
.quest_egg {
|
||||
.quest_dilatoryDistress2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1760px -537px;
|
||||
width: 165px;
|
||||
height: 207px;
|
||||
background-position: -1757px -1023px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_evilsanta {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1760px -1198px;
|
||||
width: 118px;
|
||||
height: 131px;
|
||||
}
|
||||
.quest_evilsanta2 {
|
||||
.quest_dilatoryDistress3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -220px -232px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_falcon {
|
||||
.quest_dilatory_derby {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -220px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_dolphin {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -440px -232px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_ferret {
|
||||
.quest_dustbunnies {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -663px 0px;
|
||||
background-position: -660px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_frog {
|
||||
.quest_egg {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1320px -1112px;
|
||||
width: 221px;
|
||||
height: 213px;
|
||||
background-position: -1757px -362px;
|
||||
width: 165px;
|
||||
height: 207px;
|
||||
}
|
||||
.quest_ghost_stag {
|
||||
.quest_evilsanta {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: 0px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
background-position: -1757px -1174px;
|
||||
width: 118px;
|
||||
height: 131px;
|
||||
}
|
||||
.quest_goldenknight1 {
|
||||
.quest_evilsanta2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -220px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_falcon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -440px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_ferret {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -660px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_frog {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1100px -1112px;
|
||||
width: 221px;
|
||||
height: 213px;
|
||||
}
|
||||
.quest_ghost_stag {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -880px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_goldenknight1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -880px -440px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_goldenknight2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -251px -1546px;
|
||||
background-position: 0px -1546px;
|
||||
width: 250px;
|
||||
height: 150px;
|
||||
}
|
||||
@@ -78,19 +108,19 @@
|
||||
}
|
||||
.quest_gryphon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -880px -1332px;
|
||||
background-position: -1314px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_guineapig {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -883px -220px;
|
||||
background-position: -660px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_harpy {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -883px -440px;
|
||||
background-position: -880px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -102,19 +132,19 @@
|
||||
}
|
||||
.quest_hippo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -220px -672px;
|
||||
background-position: -1100px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_horse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -440px -672px;
|
||||
background-position: -1100px -440px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_kangaroo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -660px -672px;
|
||||
background-position: -1100px -660px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -126,85 +156,85 @@
|
||||
}
|
||||
.quest_lostMasterclasser1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1103px 0px;
|
||||
background-position: -220px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_lostMasterclasser2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1103px -220px;
|
||||
background-position: -440px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_lostMasterclasser3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1103px -440px;
|
||||
background-position: -660px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_mayhemMistiflying1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1760px -896px;
|
||||
background-position: -1757px -872px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_mayhemMistiflying2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: 0px -892px;
|
||||
background-position: -1100px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_mayhemMistiflying3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -220px -892px;
|
||||
background-position: -1320px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_monkey {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -440px -892px;
|
||||
background-position: -1320px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moon1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1543px -651px;
|
||||
background-position: -1540px -217px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_moon2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -880px -892px;
|
||||
background-position: -220px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moon3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1100px -892px;
|
||||
background-position: -1320px -880px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moonstone1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1323px 0px;
|
||||
background-position: 0px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moonstone2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1323px -220px;
|
||||
background-position: -220px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moonstone3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1323px -440px;
|
||||
background-position: -440px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_nudibranch {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1543px 0px;
|
||||
background-position: -1540px -868px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
@@ -216,73 +246,73 @@
|
||||
}
|
||||
.quest_owl {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: 0px -1112px;
|
||||
background-position: -660px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_peacock {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1543px -217px;
|
||||
background-position: -1540px 0px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_penguin {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1760px -353px;
|
||||
background-position: -1757px -178px;
|
||||
width: 190px;
|
||||
height: 183px;
|
||||
}
|
||||
.quest_pterodactyl {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -660px -1112px;
|
||||
background-position: -1320px -440px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_rat {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -880px -1112px;
|
||||
background-position: -880px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_rock {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1543px -868px;
|
||||
background-position: -1540px -651px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_rooster {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1760px 0px;
|
||||
background-position: -1531px -1332px;
|
||||
width: 213px;
|
||||
height: 174px;
|
||||
}
|
||||
.quest_sabretooth {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1100px -1112px;
|
||||
background-position: 0px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_seaserpent {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -440px -1112px;
|
||||
background-position: -1100px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_sheep {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -220px -1112px;
|
||||
background-position: -440px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_slime {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1323px -880px;
|
||||
background-position: 0px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_sloth {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -660px -892px;
|
||||
background-position: -880px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -294,109 +324,79 @@
|
||||
}
|
||||
.quest_snake {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1097px -1332px;
|
||||
background-position: -1322px -1112px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_spider {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: 0px -1546px;
|
||||
background-position: -251px -1546px;
|
||||
width: 250px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_squirrel {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1103px -660px;
|
||||
background-position: 0px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_stoikalmCalamity1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1760px -745px;
|
||||
background-position: -1757px -570px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_stoikalmCalamity2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -880px -672px;
|
||||
background-position: -660px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_stoikalmCalamity3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: 0px -672px;
|
||||
background-position: 0px -232px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_taskwoodsTerror1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1760px -1047px;
|
||||
background-position: -1757px -721px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_taskwoodsTerror2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1543px -434px;
|
||||
background-position: -1540px -434px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_taskwoodsTerror3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -883px 0px;
|
||||
background-position: -440px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_treeling {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1531px -1332px;
|
||||
background-position: -1097px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_trex {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1760px -175px;
|
||||
background-position: -1757px 0px;
|
||||
width: 204px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_trex_undead {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1543px -1085px;
|
||||
background-position: -880px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_triceratops {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -440px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_turtle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -663px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_unicorn {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: 0px -232px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_velociraptor {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -220px 0px;
|
||||
width: 222px;
|
||||
height: 225px;
|
||||
}
|
||||
.quest_vice1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -1314px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_vice2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-12.png');
|
||||
background-position: -660px -452px;
|
||||
background-position: -880px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 491 KiB After Width: | Height: | Size: 491 KiB |
|
Before Width: | Height: | Size: 610 KiB After Width: | Height: | Size: 626 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 414 KiB After Width: | Height: | Size: 420 KiB |
|
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 210 KiB |
|
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 165 KiB |
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 115 KiB |
@@ -1,13 +1,10 @@
|
||||
// Colors taken from the Habitica Color Palette
|
||||
// The palette is available at TODO ADD LINK TO PALETTE PDF
|
||||
// The palette is available at https://habitica.fandom.com/wiki/Guidance_for_Comrades?file=Color_palette_official.png
|
||||
// The colors are named from the darkest to the lightest
|
||||
|
||||
$white: #FFFFFF;
|
||||
$black: #1A181D;
|
||||
|
||||
$header-color: #D5C8FF;
|
||||
$header-dark-background: #271B3D;
|
||||
|
||||
$gray-10: #34313A;
|
||||
$gray-50: #4E4A57;
|
||||
$gray-100: #686274;
|
||||
@@ -18,13 +15,7 @@ $gray-500: #E1E0E3;
|
||||
$gray-600: #EDECEE;
|
||||
$gray-700: #F9F9F9;
|
||||
|
||||
$purple-50: #36205D;
|
||||
$purple-100: #432874;
|
||||
$purple-200: #4F2A93;
|
||||
$purple-300: #6133B4;
|
||||
$purple-400: #9A62FF;
|
||||
$purple-500: #BDA8FF;
|
||||
|
||||
$red-1: #6C0406;
|
||||
$red-10: #F23035;
|
||||
$red-50: #F74E52;
|
||||
$red-100: #FF6165;
|
||||
@@ -35,39 +26,55 @@ $maroon-50: #C92B2B;
|
||||
$maroon-100: #DE3F3F;
|
||||
$maroon-500: #F19595;
|
||||
|
||||
$yellow-5: #EE9109;
|
||||
$yellow-10: #FFA623;
|
||||
$yellow-50: #FFB445;
|
||||
$yellow-100: #FFBE5D;
|
||||
$yellow-500: #FFD9A0;
|
||||
|
||||
$orange-1: #7F3300;
|
||||
$orange-10: #F47825;
|
||||
$orange-50: #FA8537;
|
||||
$orange-100: #FF944C;
|
||||
$orange-500: #FFBF98;
|
||||
$orange-500: #FFC8A7;
|
||||
|
||||
$yellow-1: #794B00;
|
||||
$yellow-5: #EE9109;
|
||||
$yellow-10: #FFA624;
|
||||
$yellow-50: #FFB445;
|
||||
$yellow-100: #FFBE5D;
|
||||
$yellow-500: #FEDEAD;
|
||||
|
||||
$green-1: #005737;
|
||||
$green-10: #1CA372;
|
||||
$green-50: #20B780;
|
||||
$green-100: #24CC8F;
|
||||
$green-500: #77F4C7;
|
||||
|
||||
$teal-1: #005158;
|
||||
$teal-10: #26A0AB;
|
||||
$teal-50: #34B5C1;
|
||||
$teal-100: #3BCAD7;
|
||||
$teal-500: #8EEDF6;
|
||||
|
||||
$blue-1: #033F5E;
|
||||
$blue-10: #2995CD;
|
||||
$blue-50: #46A7D9;
|
||||
$blue-100: #50B5E9;
|
||||
$blue-500: #A9DCF6;
|
||||
|
||||
$teal-10: #20B2BF;
|
||||
$teal-50: #3BCAD7;
|
||||
$teal-100: #5EDDE9;
|
||||
$teal-500: #A5F7FF;
|
||||
$purple-50: #36205D;
|
||||
$purple-100: #432874;
|
||||
$purple-200: #4F2A93;
|
||||
$purple-300: #6133B4;
|
||||
$purple-400: #925CF3;
|
||||
$purple-500: #BDA8FF;
|
||||
$purple-600: #D5C8FF;
|
||||
|
||||
$green-10: #24CC8F;
|
||||
$green-50: #3FDAA2;
|
||||
$green-100: #5AEAB2;
|
||||
$green-500: #A6FFDF;
|
||||
$header-color: #D5C8FF;
|
||||
$header-dark-background: #271B3D;
|
||||
|
||||
$suggested-item-color: #D5C8FF;
|
||||
|
||||
$healer-color: #cf8229;
|
||||
$healer-color: #FFA624;
|
||||
$rogue-color: #4F2A93;
|
||||
$warrior-color: #B01515;
|
||||
$wizard-color: #1f6ea2;
|
||||
$warrior-color: #C92B2B;
|
||||
$wizard-color: #2995CD;
|
||||
|
||||
$gems-color: #24CC8F;
|
||||
$gold-color: #FFA623;
|
||||
$gold-color: #FFA624;
|
||||
$hourglass-color: #2995CD;
|
||||
|
||||
@@ -1,81 +1,86 @@
|
||||
.create-task-area {
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
top: -23px;
|
||||
z-index: 999;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.slide-tasks-btns-leave-active, .slide-tasks-btns-enter-active {
|
||||
max-width: 240px;
|
||||
overflow-x: hidden;
|
||||
transition: all 0.3s cubic-bezier(0, 1, 0.5, 1);
|
||||
}
|
||||
|
||||
.slide-tasks-btns-enter, .slide-tasks-btns-leave-to {
|
||||
max-width: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.rounded-btn {
|
||||
margin-left: 8px;
|
||||
background: $white;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 100px;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||
cursor: pointer;
|
||||
color: $gray-200;
|
||||
|
||||
&:hover:not(.create-btn) {
|
||||
color: $purple-400;
|
||||
box-shadow: 0 1px 8px 0 rgba($black, 0.12), 0 4px 4px 0 rgba($black, 0.16);
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
&.icon-habit {
|
||||
width: 24px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
&.icon-daily {
|
||||
width: 21.6px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
&.icon-todo {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
&.icon-reward {
|
||||
width: 23.4px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.create-btn {
|
||||
color: $white;
|
||||
background-color: $green-10;
|
||||
|
||||
.svg-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
transition: transform 0.3s cubic-bezier(0, 1, 0.5, 1);
|
||||
}
|
||||
|
||||
&.open {
|
||||
background: $gray-200 !important;
|
||||
|
||||
.svg-icon {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
.create-task-area {
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
top: -24px;
|
||||
z-index: 999;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.slide-tasks-btns-leave-active, .slide-tasks-btns-enter-active {
|
||||
max-width: 320px;
|
||||
transition: all 0.3s cubic-bezier(0, 1, 0.5, 1);
|
||||
}
|
||||
|
||||
.slide-tasks-btns-enter, .slide-tasks-btns-leave-to {
|
||||
max-width: 0;
|
||||
opacity: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.diamond-btn {
|
||||
margin-left: 24px;
|
||||
background: $white;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||
cursor: pointer;
|
||||
color: $gray-200;
|
||||
transform: rotate(45deg);
|
||||
|
||||
&:hover:not(.create-btn) {
|
||||
color: $purple-400;
|
||||
box-shadow: 0 1px 8px 0 rgba($black, 0.12), 0 4px 4px 0 rgba($black, 0.16);
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
transform: rotate(-45deg);
|
||||
|
||||
&.icon-habit {
|
||||
width: 24px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
&.icon-daily {
|
||||
width: 21.6px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
&.icon-todo {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
&.icon-reward {
|
||||
width: 23.4px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.create-btn {
|
||||
color: $white;
|
||||
background-color: $green-100;
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
|
||||
.svg-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
transform: rotate(-45deg);
|
||||
transition: transform 0.3s cubic-bezier(0, 1, 0.5, 1);
|
||||
}
|
||||
|
||||
&.open {
|
||||
background: $gray-200 !important;
|
||||
|
||||
.svg-icon {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.popover-title-only {
|
||||
color: $white;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.popover-body {
|
||||
padding: 12px 16px;
|
||||
text-align: center;
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
&-good { // green
|
||||
&-control {
|
||||
&-bg {
|
||||
background: $green-10 !important;
|
||||
background: $green-100 !important;
|
||||
&:hover {
|
||||
.habit-control { background: rgba(26, 24, 29, 0.48) !important; }
|
||||
.daily-todo-control { background: rgba(255, 255, 255, 0.72) !important; }
|
||||
@@ -151,7 +151,7 @@
|
||||
}
|
||||
|
||||
&-modal {
|
||||
&-bg { background: $green-10 !important; }
|
||||
&-bg { background: $green-100 !important; }
|
||||
&-icon { color: $green-10 !important; }
|
||||
&-text { color: #1ca372 !important; }
|
||||
&-option-disabled:hover {
|
||||
@@ -168,7 +168,7 @@
|
||||
&-better { // teal
|
||||
&-control {
|
||||
&-bg {
|
||||
background: $teal-50 !important;
|
||||
background: $teal-100 !important;
|
||||
&:hover {
|
||||
.habit-control { background: rgba(26, 24, 29, 0.48) !important; }
|
||||
.daily-todo-control { background: rgba(255, 255, 255, 0.72) !important; }
|
||||
@@ -176,19 +176,19 @@
|
||||
}
|
||||
&-inner-habit { background: rgba(26, 24, 29, 0.24) !important; }
|
||||
&-inner-daily-todo { background: #8dedf6 !important; }
|
||||
&-checkbox { color: $teal-50 !important; }
|
||||
&-checkbox { color: $teal-100 !important; }
|
||||
}
|
||||
|
||||
&-modal {
|
||||
&-bg { background: $teal-50 !important; }
|
||||
&-icon { color: $teal-50 !important; }
|
||||
&-bg { background: $teal-100 !important; }
|
||||
&-icon { color: $teal-100 !important; }
|
||||
&-text { color: $teal-10 !important; }
|
||||
&-option-disabled:hover {
|
||||
.svg-icon { color: $teal-50 !important; }
|
||||
.svg-icon { color: $teal-100 !important; }
|
||||
.option-item-label { color: $teal-10 !important; }
|
||||
}
|
||||
&-habit-control-disabled:hover {
|
||||
.habit-control { background: $teal-50 !important; }
|
||||
.habit-control { background: $teal-100 !important; }
|
||||
.option-item-label { color: $teal-10 !important; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// possible values are: normal, fall, habitoween, thanksgiving, winter, nye, birthday, valentines, spring, summer
|
||||
// more to be added on future seasons
|
||||
|
||||
$npc_market_flavor: 'summer';
|
||||
$npc_quests_flavor: 'summer';
|
||||
$npc_seasonal_flavor: 'summer';
|
||||
$npc_timetravelers_flavor: 'summer';
|
||||
$npc_tavern_flavor: 'summer';
|
||||
$npc_market_flavor: 'normal';
|
||||
$npc_quests_flavor: 'normal';
|
||||
$npc_seasonal_flavor: 'normal';
|
||||
$npc_timetravelers_flavor: 'normal';
|
||||
$npc_tavern_flavor: 'normal';
|
||||
|
||||
@@ -164,31 +164,30 @@ export default {
|
||||
classGear (heroClass) {
|
||||
if (heroClass === 'rogue') {
|
||||
return {
|
||||
armor: 'armor_special_summer2019Rogue',
|
||||
head: 'head_special_summer2019Rogue',
|
||||
shield: 'shield_special_summer2019Rogue',
|
||||
weapon: 'weapon_special_summer2019Rogue',
|
||||
armor: 'armor_rogue_5',
|
||||
head: 'head_rogue_5',
|
||||
shield: 'shield_rogue_6',
|
||||
weapon: 'weapon_rogue_6',
|
||||
};
|
||||
} else if (heroClass === 'wizard') {
|
||||
return {
|
||||
armor: 'armor_special_summer2019Mage',
|
||||
head: 'head_special_summer2019Mage',
|
||||
shield: 'shield_special_summer2019Mage',
|
||||
weapon: 'weapon_special_summer2019Mage',
|
||||
armor: 'armor_wizard_5',
|
||||
head: 'head_wizard_5',
|
||||
weapon: 'weapon_wizard_6',
|
||||
};
|
||||
} else if (heroClass === 'healer') {
|
||||
return {
|
||||
armor: 'armor_special_summer2019Healer',
|
||||
head: 'head_special_summer2019Healer',
|
||||
shield: 'shield_special_summer2019Healer',
|
||||
weapon: 'weapon_special_summer2019Healer',
|
||||
armor: 'armor_healer_5',
|
||||
head: 'head_healer_5',
|
||||
shield: 'shield_healer_5',
|
||||
weapon: 'weapon_healer_6',
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
armor: 'armor_special_summer2019Warrior',
|
||||
head: 'head_special_summer2019Warrior',
|
||||
shield: 'shield_special_summer2019Warrior',
|
||||
weapon: 'weapon_special_summer2019Warrior',
|
||||
armor: 'armor_warrior_5',
|
||||
head: 'head_warrior_5',
|
||||
shield: 'shield_warrior_5',
|
||||
weapon: 'weapon_warrior_6',
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -113,11 +113,11 @@
|
||||
.footer-row {
|
||||
margin: 0;
|
||||
flex: 0 1 auto;
|
||||
z-index: 17;
|
||||
}
|
||||
|
||||
footer {
|
||||
color: #c3c0c7;
|
||||
z-index: 17;
|
||||
padding-bottom: 3em;
|
||||
|
||||
a {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template lang="pug">
|
||||
.row
|
||||
challenge-modal(v-on:updatedChallenge='updatedChallenge')
|
||||
challenge-modal(@updatedChallenge='updatedChallenge')
|
||||
leave-challenge-modal(:challengeId='challenge._id')
|
||||
close-challenge-modal(:members='members', :challengeId='challenge._id', :prize='challenge.prize')
|
||||
challenge-member-progress-modal(:challengeId='challenge._id')
|
||||
@@ -47,8 +47,8 @@
|
||||
@cancel="cancelTaskModal()",
|
||||
ref="taskModal",
|
||||
:challengeId="challengeId",
|
||||
v-on:taskCreated='taskCreated',
|
||||
v-on:taskEdited='taskEdited',
|
||||
@taskCreated='taskCreated',
|
||||
@taskEdited='taskEdited',
|
||||
@taskDestroyed='taskDestroyed'
|
||||
)
|
||||
.row
|
||||
@@ -57,7 +57,8 @@
|
||||
:type="column",
|
||||
:key="column",
|
||||
:taskListOverride='tasksByType[column]',
|
||||
v-on:editTask="editTask",
|
||||
@editTask="editTask",
|
||||
@taskDestroyed="taskDestroyed",
|
||||
v-if='tasksByType[column].length > 0')
|
||||
.col-12.col-md-4.sidebar.standard-page
|
||||
.button-container(v-if='canJoin')
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
.autocomplete-results.d-flex.align-items-center(
|
||||
v-for='result in searchResults',
|
||||
@click='select(result)',
|
||||
@mouseenter='result.hover = true',
|
||||
@mouseleave='result.hover = false',
|
||||
@mouseenter='setHover(result)',
|
||||
@mouseleave='resetSelection()',
|
||||
:class='{"hover-background": result.hover}',
|
||||
)
|
||||
span
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
.hover-background {
|
||||
background-color: rgba(213, 200, 255, 0.32);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.hover-foreground {
|
||||
@@ -86,6 +87,7 @@ export default {
|
||||
tier9,
|
||||
tierNPC,
|
||||
}),
|
||||
selected: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -120,12 +122,6 @@ export default {
|
||||
mounted () {
|
||||
this.grabUserNames();
|
||||
},
|
||||
created () {
|
||||
document.addEventListener('keyup', this.handleEsc);
|
||||
},
|
||||
destroyed () {
|
||||
document.removeEventListener('keyup', this.handleEsc);
|
||||
},
|
||||
watch: {
|
||||
text (newText) {
|
||||
if (!newText[newText.length - 1] || newText[newText.length - 1] === ' ') {
|
||||
@@ -154,6 +150,7 @@ export default {
|
||||
this.searchActive = false;
|
||||
this.searchEscaped = false;
|
||||
this.tmpSelections = [];
|
||||
this.resetSelection();
|
||||
},
|
||||
grabUserNames () {
|
||||
let usersThatMessage = groupBy(this.chat, 'user');
|
||||
@@ -189,13 +186,50 @@ export default {
|
||||
const targetName = `${result.username || result.displayName} `;
|
||||
newText = newText.replace(new RegExp(`${this.currentSearch}$`), targetName);
|
||||
this.$emit('select', newText);
|
||||
this.resetSelection();
|
||||
},
|
||||
handleEsc (e) {
|
||||
if (e.keyCode === 27) {
|
||||
this.searchActive = false;
|
||||
this.searchEscaped = true;
|
||||
setHover (result) {
|
||||
this.resetSelection();
|
||||
result.hover = true;
|
||||
},
|
||||
clearHover () {
|
||||
for (const selection of this.searchResults) {
|
||||
selection.hover = false;
|
||||
}
|
||||
},
|
||||
resetSelection () {
|
||||
this.clearHover();
|
||||
this.selected = null;
|
||||
},
|
||||
selectNext () {
|
||||
if (this.searchResults.length > 0) {
|
||||
this.clearHover();
|
||||
this.selected = this.selected === null ?
|
||||
0 :
|
||||
(this.selected + 1) % this.searchResults.length;
|
||||
this.searchResults[this.selected].hover = true;
|
||||
}
|
||||
},
|
||||
selectPrevious () {
|
||||
if (this.searchResults.length > 0) {
|
||||
this.clearHover();
|
||||
this.selected = this.selected === null ?
|
||||
this.searchResults.length - 1 :
|
||||
(this.selected - 1 + this.searchResults.length) % this.searchResults.length;
|
||||
this.searchResults[this.selected].hover = true;
|
||||
}
|
||||
},
|
||||
makeSelection () {
|
||||
if (this.searchResults.length > 0 && this.selected !== null) {
|
||||
const result = this.searchResults[this.selected];
|
||||
this.select(result);
|
||||
}
|
||||
},
|
||||
cancel () {
|
||||
this.searchActive = false;
|
||||
this.searchEscaped = true;
|
||||
this.resetSelection();
|
||||
},
|
||||
},
|
||||
mixins: [styleHelper],
|
||||
};
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<template lang="pug">
|
||||
div
|
||||
.mentioned-icon(v-if='isUserMentioned')
|
||||
.message-hidden(v-if='!inbox && msg.flagCount === 1 && user.contributor.admin') Message flagged once, not hidden
|
||||
.message-hidden(v-if='!inbox && msg.flagCount > 1 && user.contributor.admin') Message hidden
|
||||
.message-hidden(v-if='!inbox && user.contributor.admin && msg.flagCount') {{flagCountDescription}}
|
||||
.card-body
|
||||
user-link(:userId="msg.uuid", :name="msg.user", :backer="msg.backer", :contributor="msg.contributor")
|
||||
p.time
|
||||
@@ -137,7 +136,8 @@ import copyIcon from 'assets/svg/copy.svg';
|
||||
import likeIcon from 'assets/svg/like.svg';
|
||||
import likedIcon from 'assets/svg/liked.svg';
|
||||
import reportIcon from 'assets/svg/report.svg';
|
||||
import {highlightUsers} from '../../libs/highlightUsers';
|
||||
import { highlightUsers } from '../../libs/highlightUsers';
|
||||
import { CHAT_FLAG_LIMIT_FOR_HIDING, CHAT_FLAG_FROM_SHADOW_MUTE } from '../../../common/script/constants';
|
||||
|
||||
export default {
|
||||
components: {userLink},
|
||||
@@ -210,6 +210,12 @@ export default {
|
||||
isMessageReported () {
|
||||
return this.msg.flags && this.msg.flags[this.user.id] || this.reported;
|
||||
},
|
||||
flagCountDescription () {
|
||||
if (!this.msg.flagCount) return '';
|
||||
if (this.msg.flagCount < CHAT_FLAG_LIMIT_FOR_HIDING) return 'Message flagged once, not hidden';
|
||||
if (this.msg.flagCount < CHAT_FLAG_FROM_SHADOW_MUTE) return 'Message hidden';
|
||||
return 'Message hidden (shadow-muted)';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async like () {
|
||||
@@ -273,5 +279,10 @@ export default {
|
||||
return habiticaMarkdown.render(String(text));
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.CHAT_FLAG_LIMIT_FOR_HIDING = CHAT_FLAG_LIMIT_FOR_HIDING;
|
||||
this.CHAT_FLAG_FROM_SHADOW_MUTE = CHAT_FLAG_FROM_SHADOW_MUTE;
|
||||
this.$emit('chat-card-mounted', this.msg.id);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
<template lang="pug">
|
||||
.container-fluid
|
||||
.container-fluid(ref="container")
|
||||
.row
|
||||
.col-12
|
||||
copy-as-todo-modal(:group-type='groupType', :group-name='groupName', :group-id='groupId')
|
||||
.row.loadmore
|
||||
div(v-if="canLoadMore")
|
||||
.loadmore-divider
|
||||
button.btn.btn-secondary(@click='triggerLoad()') {{ $t('loadEarlierMessages') }}
|
||||
.loadmore-divider
|
||||
h2.col-12.loading(v-show="isLoading") {{ $t('loading') }}
|
||||
div(v-for="(msg, index) in messages", v-if='chat && canViewFlag(msg)', :class='{row: inbox}')
|
||||
.d-flex(v-if='user._id !== msg.uuid', :class='{"flex-grow-1": inbox}')
|
||||
avatar.avatar-left(
|
||||
@@ -21,7 +27,8 @@
|
||||
:groupId='groupId',
|
||||
@message-liked='messageLiked',
|
||||
@message-removed='messageRemoved',
|
||||
@show-member-modal='showMemberModal')
|
||||
@show-member-modal='showMemberModal',
|
||||
@chat-card-mounted='itemWasMounted')
|
||||
.d-flex(v-if='user._id === msg.uuid', :class='{"flex-grow-1": inbox}')
|
||||
.card(:class='{"col-10": inbox}')
|
||||
chat-card(
|
||||
@@ -30,7 +37,8 @@
|
||||
:groupId='groupId',
|
||||
@message-liked='messageLiked',
|
||||
@message-removed='messageRemoved',
|
||||
@show-member-modal='showMemberModal')
|
||||
@show-member-modal='showMemberModal',
|
||||
@chat-card-mounted='itemWasMounted')
|
||||
avatar(
|
||||
v-if='msg.userStyles || (cachedProfileData[msg.uuid] && !cachedProfileData[msg.uuid].rejected)',
|
||||
:member="msg.userStyles || cachedProfileData[msg.uuid]",
|
||||
@@ -49,6 +57,34 @@
|
||||
width: 10%;
|
||||
min-width: 7rem;
|
||||
}
|
||||
.loadmore {
|
||||
justify-content: center;
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
|
||||
button {
|
||||
text-align: center;
|
||||
color: $gray-50;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loadmore-divider {
|
||||
height: 1px;
|
||||
background-color: $gray-500;
|
||||
flex: 1;
|
||||
margin-left: 24px;
|
||||
margin-right: 24px;
|
||||
|
||||
&:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-left {
|
||||
margin-left: -1.5rem;
|
||||
@@ -97,6 +133,8 @@
|
||||
.message-scroll .d-flex {
|
||||
min-width: 1px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -120,6 +158,9 @@ export default {
|
||||
groupType: {},
|
||||
groupId: {},
|
||||
groupName: {},
|
||||
|
||||
isLoading: Boolean,
|
||||
canLoadMore: Boolean,
|
||||
},
|
||||
components: {
|
||||
copyAsTodoModal,
|
||||
@@ -142,6 +183,8 @@ export default {
|
||||
currentProfileLoadedCount: 0,
|
||||
currentProfileLoadedEnd: 10,
|
||||
loading: false,
|
||||
handleScrollBack: false,
|
||||
lastOffset: -1,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -153,15 +196,24 @@ export default {
|
||||
return this.chat;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
messages () {
|
||||
this.loadProfileCache();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleScroll () {
|
||||
this.loadProfileCache(window.scrollY / 1000);
|
||||
},
|
||||
async triggerLoad () {
|
||||
const container = this.$refs.container;
|
||||
|
||||
// get current offset
|
||||
this.lastOffset = container.scrollTop - (container.scrollHeight - container.clientHeight);
|
||||
// disable scroll
|
||||
container.style.overflowY = 'hidden';
|
||||
|
||||
const canLoadMore = this.inbox && !this.isLoading && this.canLoadMore;
|
||||
if (canLoadMore) {
|
||||
await this.$emit('triggerLoad');
|
||||
this.handleScrollBack = true;
|
||||
}
|
||||
},
|
||||
canViewFlag (message) {
|
||||
if (message.uuid === this.user._id) return true;
|
||||
if (!message.flagCount || message.flagCount < 2) return true;
|
||||
@@ -252,6 +304,20 @@ export default {
|
||||
this.$router.push({name: 'userProfile', params: {userId: profile._id}});
|
||||
}
|
||||
},
|
||||
itemWasMounted: debounce(function itemWasMounted () {
|
||||
if (this.handleScrollBack) {
|
||||
this.handleScrollBack = false;
|
||||
|
||||
const container = this.$refs.container;
|
||||
const offset = container.scrollHeight - container.clientHeight;
|
||||
|
||||
const newOffset = offset + this.lastOffset;
|
||||
|
||||
container.scrollTo(0, newOffset);
|
||||
// enable scroll again
|
||||
container.style.overflowY = 'scroll';
|
||||
}
|
||||
}, 50),
|
||||
messageLiked (message) {
|
||||
const chatIndex = findIndex(this.chat, chatMessage => {
|
||||
return chatMessage.id === message.id;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
.create-task-area.d-flex(v-if='canCreateTasks')
|
||||
transition(name="slide-tasks-btns")
|
||||
.d-flex(v-if="openCreateBtn")
|
||||
.create-task-btn.rounded-btn(
|
||||
.create-task-btn.diamond-btn(
|
||||
v-for="type in columns",
|
||||
:key="type",
|
||||
@click="createTask(type)",
|
||||
@@ -28,7 +28,7 @@
|
||||
)
|
||||
.svg-icon(v-html="icons[type]", :class='`icon-${type}`')
|
||||
|
||||
#create-task-btn.create-btn.rounded-btn.btn.btn-success(
|
||||
#create-task-btn.create-btn.diamond-btn.btn.btn-success(
|
||||
@click="openCreateBtn = !openCreateBtn",
|
||||
:class="{open: openCreateBtn}",
|
||||
)
|
||||
|
||||
@@ -11,11 +11,17 @@
|
||||
:class='{"user-entry": newMessage}',
|
||||
@keydown='updateCarretPosition',
|
||||
@keyup.ctrl.enter='sendMessageShortcut()',
|
||||
@keydown.tab='handleTab($event)',
|
||||
@keydown.up='selectPreviousAutocomplete($event)',
|
||||
@keydown.down='selectNextAutocomplete($event)',
|
||||
@keydown.enter='selectAutocomplete($event)',
|
||||
@keydown.esc='handleEscape($event)',
|
||||
@paste='disableMessageSendShortcut()',
|
||||
maxlength='3000'
|
||||
)
|
||||
span {{ currentLength }} / 3000
|
||||
autocomplete(
|
||||
ref='autocomplete',
|
||||
:text='newMessage',
|
||||
v-on:select="selectedAutocomplete",
|
||||
:textbox='textbox',
|
||||
@@ -165,6 +171,45 @@
|
||||
}, 500);
|
||||
},
|
||||
|
||||
handleTab (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
if (e.shiftKey) {
|
||||
this.$refs.autocomplete.selectPrevious();
|
||||
} else {
|
||||
this.$refs.autocomplete.selectNext();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleEscape (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
this.$refs.autocomplete.cancel();
|
||||
}
|
||||
},
|
||||
|
||||
selectNextAutocomplete (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
this.$refs.autocomplete.selectNext();
|
||||
}
|
||||
},
|
||||
|
||||
selectPreviousAutocomplete (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
this.$refs.autocomplete.selectPrevious();
|
||||
}
|
||||
},
|
||||
|
||||
selectAutocomplete (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
this.$refs.autocomplete.makeSelection();
|
||||
}
|
||||
},
|
||||
|
||||
selectedAutocomplete (newText) {
|
||||
this.newMessage = newText;
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
small.muted(v-html="$t('blurbHallContributors')")
|
||||
.well
|
||||
div(v-if='user.contributor.admin')
|
||||
h2 {{ $t('rewardUser') }}
|
||||
h2 Reward User
|
||||
|
||||
.row
|
||||
.form.col-6(v-if='!hero.profile')
|
||||
@@ -11,33 +11,33 @@
|
||||
input.form-control(type='text', v-model='heroID', :placeholder="'User ID or Username'")
|
||||
.form-group
|
||||
button.btn.btn-secondary(@click='loadHero(heroID)')
|
||||
| {{ $t('loadUser') }}
|
||||
| Load User
|
||||
|
||||
.row
|
||||
.form.col-6(v-if='hero && hero.profile', submit='saveHero(hero)')
|
||||
router-link(:to="{'name': 'userProfile', 'params': {'userId': hero._id}}")
|
||||
h3 {{hero.profile.name}}
|
||||
h3 @{{hero.auth.local.username}} / {{hero.profile.name}}
|
||||
.form-group
|
||||
input.form-control(type='text', v-model='hero.contributor.text', :placeholder="$t('contribTitle')")
|
||||
label Contributor Title
|
||||
input.form-control(type='text', v-model='hero.contributor.text')
|
||||
small Common titles: <strong>Ambassador, Artisan, Bard, Blacksmith, Challenger, Comrade, Fletcher, Linguist, Linguistic Scribe, Scribe, Socialite, Storyteller</strong>. Rare titles: Advisor, Chamberlain, Designer, Mathematician, Shirtster, Spokesperson, Statistician, Tinker, Transcriber, Troubadour.
|
||||
.form-group
|
||||
label {{ $t('contribLevel') }}
|
||||
label Contributor Tier
|
||||
input.form-control(type='number', v-model='hero.contributor.level')
|
||||
small {{ $t('contribHallText') }}
|
||||
small 1-7 for normal contributors, 8 for moderators, 9 for staff. This determines which items, pets, and mounts are available, and name-tag coloring. Tiers 8 and 9 are automatically given admin status.
|
||||
|
|
||||
a(target='_blank', href='https://trello.com/c/wkFzONhE/277-contributor-gear') {{ $t('moreDetails') }}
|
||||
a(target='_blank', href='https://trello.com/c/wkFzONhE/277-contributor-gear') More details (1-7)
|
||||
|,
|
||||
a(target='_blank', href='https://github.com/HabitRPG/habitica/issues/3801') {{ $t('moreDetails2') }}
|
||||
a(target='_blank', href='https://github.com/HabitRPG/habitica/issues/3801') more details (8-9)
|
||||
.form-group
|
||||
textarea.form-control(cols=5, :placeholder="$t('contributions')", v-model='hero.contributor.contributions')
|
||||
//include ../../shared/formattiv-help
|
||||
hr
|
||||
label Contributions
|
||||
textarea.form-control(cols=5, v-model='hero.contributor.contributions')
|
||||
|
||||
.form-group
|
||||
label {{ $t('balance') }}
|
||||
label Balance
|
||||
input.form-control(type='number', step="any", v-model='hero.balance')
|
||||
small
|
||||
span ‘{{ hero.balance }}’
|
||||
span(v-html='$t("notGems")')
|
||||
span '{{ hero.balance }}' is in USD, <em>not</em> in Gems. E.g., if this number is 1, it means 4 Gems. Only use this option when manually granting Gems to players, don't use it when granting contributor tiers. Contrib tiers will automatically add Gems.
|
||||
.accordion
|
||||
.accordion-group(heading='Items')
|
||||
h4.expand-toggle(:class="{'open': expandItems}", @click="expandItems = !expandItems") Update Item
|
||||
@@ -56,6 +56,11 @@
|
||||
h4.expand-toggle(:class="{'open': expandAuth}", @click="expandAuth = !expandAuth") Auth
|
||||
div(v-if="expandAuth")
|
||||
pre {{hero.auth}}
|
||||
.form-group
|
||||
.checkbox
|
||||
label
|
||||
input(type='checkbox', v-if='hero.flags', v-model='hero.flags.chatShadowMuted')
|
||||
strong Chat Shadow Muting On
|
||||
.form-group
|
||||
.checkbox
|
||||
label
|
||||
@@ -71,7 +76,7 @@
|
||||
// Add backer stuff like tier, disable adds, etcs
|
||||
.form-group
|
||||
button.form-control.btn.btn-primary(@click='saveHero()')
|
||||
| {{ $t('save') }}
|
||||
| Save
|
||||
|
||||
.table-responsive
|
||||
table.table.table-striped
|
||||
@@ -180,6 +185,7 @@ export default {
|
||||
if (!this.hero.flags) {
|
||||
this.hero.flags = {
|
||||
chatRevoked: false,
|
||||
chatShadowMuted: false,
|
||||
};
|
||||
}
|
||||
this.expandItems = false;
|
||||
|
||||
@@ -402,13 +402,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.item.currency === 'gems' &&
|
||||
!confirm(this.$t('purchaseFor', { cost: this.item.value * this.selectedAmountToBuy }))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.item.currency === 'hourglasses' &&
|
||||
!confirm(this.$t('purchaseForHourglasses', { cost: this.item.value }))) {
|
||||
const shouldConfirmPurchase = this.item.currency === 'gems' || this.item.currency === 'hourglasses';
|
||||
if (shouldConfirmPurchase && !this.confirmPurchase(this.item.currency, this.item.value * this.selectedAmountToBuy)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
h2(v-once) {{ $t('filter') }}
|
||||
.form-group
|
||||
checkbox(
|
||||
v-for="category in categories",
|
||||
:key="category.identifier",
|
||||
:id="`category-${category.identifier}`",
|
||||
:checked.sync="viewOptions[category.identifier].selected",
|
||||
:text="category.text"
|
||||
v-for="viewOptionKey in Object.keys(viewOptions)",
|
||||
:key="viewOptionKey",
|
||||
:id="`category-${viewOptionKey}`",
|
||||
:checked.sync="viewOptions[viewOptionKey].selected",
|
||||
:text="viewOptions[viewOptionKey].text"
|
||||
)
|
||||
div.form-group.clearfix
|
||||
h3.float-left(v-once) {{ $t('hideLocked') }}
|
||||
@@ -27,7 +27,7 @@
|
||||
import Checkbox from 'client/components/ui/checkbox';
|
||||
import toggleSwitch from 'client/components/ui/toggleSwitch';
|
||||
export default {
|
||||
props: ['hidePinned', 'hideLocked', 'categories', 'viewOptions'],
|
||||
props: ['hidePinned', 'hideLocked', 'viewOptions'],
|
||||
components: {
|
||||
Checkbox,
|
||||
toggleSwitch,
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
.form-group
|
||||
input.form-control.input-search(type="text", v-model="searchText", :placeholder="$t('search')")
|
||||
market-filter(
|
||||
:categories="categories",
|
||||
:hideLocked.sync="hideLocked",
|
||||
:hidePinned.sync="hidePinned",
|
||||
:viewOptions="viewOptions"
|
||||
@@ -39,7 +38,7 @@
|
||||
span.text {{ $t(ctx.item.id) }}
|
||||
div(
|
||||
v-for="category in categories",
|
||||
v-if="!anyFilterSelected || viewOptions[category.identifier].selected && category.identifier !== 'equipment'"
|
||||
v-if="!anyFilterSelected || viewOptions[category.identifier].selected"
|
||||
)
|
||||
h4 {{ category.text }}
|
||||
category-row(
|
||||
@@ -197,7 +196,12 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
viewOptions: {},
|
||||
viewOptions: {
|
||||
equipment: {
|
||||
selected: false,
|
||||
text: this.$t('equipment'),
|
||||
},
|
||||
},
|
||||
|
||||
searchText: null,
|
||||
searchTextThrottled: null,
|
||||
@@ -238,11 +242,6 @@ export default {
|
||||
...this.market.categories,
|
||||
];
|
||||
|
||||
categories.push({
|
||||
identifier: 'equipment',
|
||||
text: this.$t('equipment'),
|
||||
});
|
||||
|
||||
categories.push({
|
||||
identifier: 'cards',
|
||||
text: this.$t('cards'),
|
||||
@@ -291,6 +290,7 @@ export default {
|
||||
if (!this.viewOptions[category.identifier]) {
|
||||
this.$set(this.viewOptions, category.identifier, {
|
||||
selected: false,
|
||||
text: category.text,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -265,6 +265,9 @@
|
||||
this.$emit('change', $event);
|
||||
},
|
||||
buyItem () {
|
||||
if (!this.confirmPurchase(this.item.currency, this.item.value * this.selectedAmountToBuy)) {
|
||||
return;
|
||||
}
|
||||
this.makeGenericPurchase(this.item, 'buyQuestModal', this.selectedAmountToBuy);
|
||||
this.purchased(this.item.text);
|
||||
this.hideDialog();
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
.create-task-area.d-flex
|
||||
transition(name="slide-tasks-btns")
|
||||
.d-flex(v-if="openCreateBtn")
|
||||
.create-task-btn.rounded-btn(
|
||||
.create-task-btn.diamond-btn(
|
||||
v-for="type in columns",
|
||||
:key="type",
|
||||
@click="createTask(type)",
|
||||
@@ -83,7 +83,7 @@
|
||||
)
|
||||
.svg-icon(v-html="icons[type]", :class='`icon-${type}`')
|
||||
|
||||
#create-task-btn.create-btn.rounded-btn.btn.btn-success(
|
||||
#create-task-btn.create-btn.diamond-btn.btn.btn-success(
|
||||
@click="openCreateBtn = !openCreateBtn",
|
||||
:class="{open: openCreateBtn}",
|
||||
)
|
||||
|
||||
@@ -34,21 +34,25 @@
|
||||
.svg-icon(v-html="tierIcon(conversation)")
|
||||
.time
|
||||
span.mr-1(v-if='conversation.username') @{{ conversation.username }} •
|
||||
span {{ conversation.date | timeAgo }}
|
||||
span(v-if="conversation.date") {{ conversation.date | timeAgo }}
|
||||
div.messagePreview {{ conversation.lastMessageText ? removeTags(parseMarkdown(conversation.lastMessageText)) : '' }}
|
||||
.col-8.messages.d-flex.flex-column.justify-content-between
|
||||
.empty-messages.text-center(v-if='!selectedConversation.key')
|
||||
.svg-icon.envelope(v-html="icons.messageIcon")
|
||||
h4 {{placeholderTexts.title}}
|
||||
p(v-html="placeholderTexts.description")
|
||||
.empty-messages.text-center(v-if='selectedConversation.key && selectedConversationMessages.length === 0')
|
||||
.empty-messages.text-center(v-if='selectedConversation && selectedConversationMessages.length === 0')
|
||||
p {{ $t('beginningOfConversation', {userName: selectedConversation.name})}}
|
||||
chat-messages.message-scroll(
|
||||
v-if="selectedConversation.messages && selectedConversationMessages.length > 0",
|
||||
v-if="selectedConversation && selectedConversationMessages.length > 0",
|
||||
:chat='selectedConversationMessages',
|
||||
:inbox='true',
|
||||
@message-removed='messageRemoved',
|
||||
ref="chatscroll"
|
||||
ref="chatscroll",
|
||||
|
||||
:canLoadMore="canLoadMore",
|
||||
:isLoading="messagesLoading",
|
||||
@triggerLoad="infiniteScrollTrigger"
|
||||
)
|
||||
.pm-disabled-caption.text-center(v-if="user.inbox.optOut && selectedConversation.key")
|
||||
h4 {{$t('PMDisabledCaptionTitle')}}
|
||||
@@ -64,6 +68,12 @@
|
||||
span.ml-3 {{ currentLength }} / 3000
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
#inbox-modal .modal-body {
|
||||
padding-top: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
@import '~client/assets/scss/tiers.scss';
|
||||
@@ -94,7 +104,7 @@
|
||||
|
||||
.sidebar {
|
||||
background-color: $gray-700;
|
||||
min-height: 600px;
|
||||
min-height: 540px;
|
||||
padding: 0;
|
||||
|
||||
.search-section {
|
||||
@@ -107,6 +117,7 @@
|
||||
position: relative;
|
||||
padding-left: 0;
|
||||
padding-bottom: 6em;
|
||||
height: 540px;
|
||||
}
|
||||
|
||||
.message-scroll {
|
||||
@@ -225,8 +236,8 @@
|
||||
import Vue from 'vue';
|
||||
import moment from 'moment';
|
||||
import filter from 'lodash/filter';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import habiticaMarkdown from 'habitica-markdown';
|
||||
import styleHelper from 'client/mixins/styleHelper';
|
||||
@@ -308,8 +319,12 @@ export default {
|
||||
newMessage: '',
|
||||
showPopover: false,
|
||||
messages: [],
|
||||
messagesByConversation: {}, // cache {uuid: []}
|
||||
loadedConversations: [],
|
||||
loaded: false,
|
||||
messagesLoading: false,
|
||||
initiatedConversation: null,
|
||||
updateConversionsCounter: 0,
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
@@ -319,8 +334,11 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
canLoadMore () {
|
||||
return this.selectedConversation && this.selectedConversation.canLoadMore;
|
||||
},
|
||||
conversations () {
|
||||
const inboxGroup = groupBy(this.messages, 'uuid');
|
||||
const inboxGroup = groupBy(this.loadedConversations, 'uuid');
|
||||
|
||||
// Add placeholder for new conversations
|
||||
if (this.initiatedConversation && this.initiatedConversation.uuid) {
|
||||
@@ -328,6 +346,7 @@ export default {
|
||||
uuid: this.initiatedConversation.uuid,
|
||||
user: this.initiatedConversation.user,
|
||||
username: this.initiatedConversation.username,
|
||||
contributor: this.initiatedConversation.contributor,
|
||||
id: '',
|
||||
text: '',
|
||||
timestamp: new Date(),
|
||||
@@ -336,62 +355,56 @@ export default {
|
||||
// Create conversation objects
|
||||
const convos = [];
|
||||
for (let key in inboxGroup) {
|
||||
const convoSorted = sortBy(inboxGroup[key], [(o) => {
|
||||
return (new Date(o.timestamp)).getTime();
|
||||
}]);
|
||||
|
||||
// Fix poor inbox chat models
|
||||
const newChatModels = convoSorted.map(chat => {
|
||||
let newChat = Object.assign({}, chat);
|
||||
if (newChat.sent) {
|
||||
newChat.toUUID = newChat.uuid;
|
||||
newChat.toUser = newChat.user;
|
||||
newChat.toUserName = newChat.username;
|
||||
newChat.toUserContributor = newChat.contributor;
|
||||
newChat.toUserBacker = newChat.backer;
|
||||
newChat.uuid = this.user._id;
|
||||
newChat.user = this.user.profile.name;
|
||||
newChat.username = this.user.auth.local.username;
|
||||
newChat.contributor = this.user.contributor;
|
||||
newChat.backer = this.user.backer;
|
||||
}
|
||||
return newChat;
|
||||
});
|
||||
|
||||
// In case the last message is a placeholder, remove it
|
||||
const recentMessage = newChatModels[newChatModels.length - 1];
|
||||
if (!recentMessage.text) newChatModels.splice(newChatModels.length - 1, 1);
|
||||
const recentMessage = inboxGroup[key][0];
|
||||
|
||||
const convoModel = {
|
||||
key: recentMessage.toUUID ? recentMessage.toUUID : recentMessage.uuid,
|
||||
name: recentMessage.toUser ? recentMessage.toUser : recentMessage.user, // Handles case where from user sent the only message or the to user sent the only message
|
||||
key: recentMessage.uuid,
|
||||
name: recentMessage.user, // Handles case where from user sent the only message or the to user sent the only message
|
||||
username: !recentMessage.text ? recentMessage.username : recentMessage.toUserName,
|
||||
date: recentMessage.timestamp,
|
||||
lastMessageText: recentMessage.text,
|
||||
messages: newChatModels,
|
||||
canLoadMore: true,
|
||||
page: 0,
|
||||
};
|
||||
|
||||
convos.push(convoModel);
|
||||
}
|
||||
|
||||
// Sort models by most recent
|
||||
const conversations = sortBy(convos, [(o) => {
|
||||
return moment(o.date).toDate();
|
||||
}]);
|
||||
|
||||
return conversations.reverse();
|
||||
return convos;
|
||||
},
|
||||
// Separate from selectedConversation which is not coputed so messages don't update automatically
|
||||
// Separate from selectedConversation which is not computed so messages don't update automatically
|
||||
selectedConversationMessages () {
|
||||
// Vue-subscribe to changes
|
||||
const subScribeToUpdate = this.messagesLoading || this.updateConversionsCounter > -1;
|
||||
|
||||
|
||||
const selectedConversationKey = this.selectedConversation.key;
|
||||
const selectedConversation = this.conversations.find(c => c.key === selectedConversationKey);
|
||||
return selectedConversation ? selectedConversation.messages : [];
|
||||
const selectedConversation = this.messagesByConversation[selectedConversationKey];
|
||||
this.messages = selectedConversation || [];
|
||||
|
||||
const ordered = orderBy(this.messages, [(m) => {
|
||||
return m.timestamp;
|
||||
}], ['asc']);
|
||||
|
||||
if (subScribeToUpdate) {
|
||||
return ordered;
|
||||
}
|
||||
},
|
||||
filtersConversations () {
|
||||
if (!this.search) return this.conversations;
|
||||
return filter(this.conversations, (conversation) => {
|
||||
return conversation.name.toLowerCase().indexOf(this.search.toLowerCase()) !== -1;
|
||||
});
|
||||
// Vue-subscribe to changes
|
||||
const subScribeToUpdate = this.updateConversionsCounter > -1;
|
||||
|
||||
const filtered = subScribeToUpdate && !this.search ?
|
||||
this.conversations :
|
||||
filter(this.conversations, (conversation) => {
|
||||
return conversation.name.toLowerCase().indexOf(this.search.toLowerCase()) !== -1;
|
||||
});
|
||||
|
||||
const ordered = orderBy(filtered, [(o) => {
|
||||
return moment(o.date).toDate();
|
||||
}], ['desc']);
|
||||
|
||||
return ordered;
|
||||
},
|
||||
currentLength () {
|
||||
return this.newMessage.length;
|
||||
@@ -424,25 +437,34 @@ export default {
|
||||
methods: {
|
||||
async onModalShown () {
|
||||
this.loaded = false;
|
||||
const res = await axios.get('/api/v4/inbox/messages');
|
||||
this.messages = res.data.data;
|
||||
|
||||
const conversationRes = await axios.get('/api/v4/inbox/conversations');
|
||||
this.loadedConversations = conversationRes.data.data;
|
||||
|
||||
this.loaded = true;
|
||||
},
|
||||
onModalHide () {
|
||||
this.messages = [];
|
||||
// reset everything
|
||||
this.loadedConversations = [];
|
||||
this.loaded = false;
|
||||
this.initiatedConversation = null;
|
||||
this.messagesByConversation = {};
|
||||
this.selectedConversation = {};
|
||||
},
|
||||
messageRemoved (message) {
|
||||
const messageIndex = this.messages.findIndex(msg => msg.id === message.id);
|
||||
if (messageIndex !== -1) this.messages.splice(messageIndex, 1);
|
||||
if (this.selectedConversationMessages.length === 0) this.initiatedConversation = {
|
||||
uuid: this.selectedConversation.key,
|
||||
user: this.selectedConversation.name,
|
||||
username: this.selectedConversation.username,
|
||||
backer: this.selectedConversation.backer,
|
||||
contributor: this.selectedConversation.contributor,
|
||||
};
|
||||
const messages = this.messagesByConversation[this.selectedConversation.key];
|
||||
|
||||
const messageIndex = messages.findIndex(msg => msg.id === message.id);
|
||||
if (messageIndex !== -1) messages.splice(messageIndex, 1);
|
||||
if (this.selectedConversationMessages.length === 0) {
|
||||
this.initiatedConversation = {
|
||||
uuid: this.selectedConversation.key,
|
||||
user: this.selectedConversation.name,
|
||||
username: this.selectedConversation.username,
|
||||
backer: this.selectedConversation.backer,
|
||||
contributor: this.selectedConversation.contributor,
|
||||
};
|
||||
}
|
||||
},
|
||||
toggleClick () {
|
||||
this.displayCreate = !this.displayCreate;
|
||||
@@ -450,13 +472,17 @@ export default {
|
||||
toggleOpt () {
|
||||
this.$store.dispatch('user:togglePrivateMessagesOpt');
|
||||
},
|
||||
selectConversation (key) {
|
||||
async selectConversation (key) {
|
||||
let convoFound = this.conversations.find((conversation) => {
|
||||
return conversation.key === key;
|
||||
});
|
||||
|
||||
this.selectedConversation = convoFound || {};
|
||||
|
||||
if (!this.messagesByConversation[this.selectedConversation.key]) {
|
||||
await this.loadMessages();
|
||||
}
|
||||
|
||||
Vue.nextTick(() => {
|
||||
if (!this.$refs.chatscroll) return;
|
||||
let chatscroll = this.$refs.chatscroll.$el;
|
||||
@@ -466,18 +492,32 @@ export default {
|
||||
sendPrivateMessage () {
|
||||
if (!this.newMessage) return;
|
||||
|
||||
this.messages.push({
|
||||
const messages = this.messagesByConversation[this.selectedConversation.key];
|
||||
|
||||
messages.push({
|
||||
sent: true,
|
||||
text: this.newMessage,
|
||||
timestamp: new Date(),
|
||||
user: this.selectedConversation.name,
|
||||
username: this.selectedConversation.username,
|
||||
uuid: this.selectedConversation.key,
|
||||
toUser: this.selectedConversation.name,
|
||||
toUserName: this.selectedConversation.username,
|
||||
toUserContributor: this.selectedConversation.contributor,
|
||||
toUserBacker: this.selectedConversation.backer,
|
||||
toUUID: this.selectedConversation.uuid,
|
||||
|
||||
id: '-1', // will be updated once the result is back
|
||||
likes: {},
|
||||
ownerId: this.user._id,
|
||||
uuid: this.user._id,
|
||||
fromUUID: this.user._id,
|
||||
user: this.user.profile.name,
|
||||
username: this.user.auth.local.username,
|
||||
contributor: this.user.contributor,
|
||||
backer: this.user.backer,
|
||||
});
|
||||
|
||||
// Remove the placeholder message
|
||||
if (this.initiatedConversation && this.initiatedConversation.uuid === this.selectedConversation.key) {
|
||||
this.loadedConversations.unshift(this.initiatedConversation);
|
||||
this.initiatedConversation = null;
|
||||
}
|
||||
|
||||
@@ -495,7 +535,10 @@ export default {
|
||||
message: this.newMessage,
|
||||
}).then(response => {
|
||||
const newMessage = response.data.data.message;
|
||||
Object.assign(this.messages[this.messages.length - 1], newMessage);
|
||||
const messageToReset = messages[messages.length - 1];
|
||||
messageToReset.id = newMessage.id; // just set the id, all other infos already set
|
||||
Object.assign(messages[messages.length - 1], messageToReset);
|
||||
this.updateConversionsCounter++;
|
||||
});
|
||||
|
||||
this.newMessage = '';
|
||||
@@ -520,6 +563,36 @@ export default {
|
||||
if (!text) return;
|
||||
return habiticaMarkdown.render(String(text));
|
||||
},
|
||||
infiniteScrollTrigger () {
|
||||
// show loading and wait until the loadMore debounced
|
||||
// or else it would trigger on every scrolling-pixel (while not loading)
|
||||
if (this.canLoadMore) {
|
||||
this.messagesLoading = true;
|
||||
}
|
||||
|
||||
return this.loadMore();
|
||||
},
|
||||
loadMore () {
|
||||
this.selectedConversation.page += 1;
|
||||
return this.loadMessages();
|
||||
},
|
||||
async loadMessages () {
|
||||
this.messagesLoading = true;
|
||||
|
||||
const requestUrl = `/api/v4/inbox/paged-messages?conversation=${this.selectedConversation.key}&page=${this.selectedConversation.page}`;
|
||||
const res = await axios.get(requestUrl);
|
||||
const loadedMessages = res.data.data;
|
||||
|
||||
this.messagesByConversation[this.selectedConversation.key] = this.messagesByConversation[this.selectedConversation.key] || [];
|
||||
const loadedMessagesToAdd = loadedMessages
|
||||
.filter(m => this.messagesByConversation[this.selectedConversation.key].findIndex(mI => mI.id === m.id) === -1)
|
||||
;
|
||||
this.messagesByConversation[this.selectedConversation.key].push(...loadedMessagesToAdd);
|
||||
|
||||
// only show the load more Button if the max count was returned
|
||||
this.selectedConversation.canLoadMore = loadedMessages.length === 10;
|
||||
this.messagesLoading = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -12,22 +12,29 @@
|
||||
button.btn.btn-secondary.positive-icon(v-if='user._id !== this.userLoggedIn._id && userLoggedIn.inbox.blocks.indexOf(user._id) !== -1',
|
||||
@click="unblockUser()", v-b-tooltip.hover.right="$t('unblock')")
|
||||
.svg-icon.positive-icon(v-html="icons.positive")
|
||||
button.btn.btn-secondary.positive-icon(v-if='this.userLoggedIn.contributor.admin && !adminToolsLoaded',
|
||||
@click="loadAdminTools()", v-b-tooltip.hover.right="'Admin - Load Tools'")
|
||||
button.btn.btn-secondary.positive-icon(v-if='this.userLoggedIn.contributor.admin',
|
||||
@click="toggleAdminTools()", v-b-tooltip.hover.right="'Admin - Toggle Tools'")
|
||||
.svg-icon.positive-icon(v-html="icons.staff")
|
||||
span(v-if='this.userLoggedIn.contributor.admin && adminToolsLoaded')
|
||||
button.btn.btn-secondary.positive-icon(v-if='!hero.flags || (hero.flags && !hero.flags.chatRevoked)',
|
||||
@click="adminRevokeChat()", v-b-tooltip.hover.bottom="'Admin - Revoke Chat Privileges'")
|
||||
.svg-icon.positive-icon(v-html="icons.megaphone")
|
||||
button.btn.btn-secondary.positive-icon(v-if='hero.flags && hero.flags.chatRevoked',
|
||||
@click="adminReinstateChat()", v-b-tooltip.hover.bottom="'Admin - Reinstate Chat Privileges'")
|
||||
.svg-icon.positive-icon(v-html="icons.challenge")
|
||||
button.btn.btn-secondary.positive-icon(v-if='!hero.auth.blocked',
|
||||
@click="adminBlockUser()", v-b-tooltip.hover.right="'Admin - Ban User'")
|
||||
.svg-icon.positive-icon(v-html="icons.lock")
|
||||
button.btn.btn-secondary.positive-icon(v-if='hero.auth.blocked',
|
||||
@click="adminUnblockUser()", v-b-tooltip.hover.right="'Admin - Unblock User'")
|
||||
.svg-icon.positive-icon(v-html="icons.member")
|
||||
.row.admin-profile-actions(v-if='this.userLoggedIn.contributor.admin && adminToolsLoaded')
|
||||
.col-12.text-right
|
||||
span.admin-action(v-if='!hero.flags || (hero.flags && !hero.flags.chatShadowMuted)',
|
||||
@click="adminTurnOnShadowMuting()", v-b-tooltip.hover.bottom="'Turn on Shadow Muting'")
|
||||
| shadow-mute
|
||||
span.admin-action(v-if='hero.flags && hero.flags.chatShadowMuted',
|
||||
@click="adminTurnOffShadowMuting()", v-b-tooltip.hover.bottom="'Turn off Shadow Muting'")
|
||||
| un-shadow-mute
|
||||
span.admin-action(v-if='!hero.flags || (hero.flags && !hero.flags.chatRevoked)',
|
||||
@click="adminRevokeChat()", v-b-tooltip.hover.bottom="'Revoke Chat Privileges'")
|
||||
| mute
|
||||
span.admin-action(v-if='hero.flags && hero.flags.chatRevoked',
|
||||
@click="adminReinstateChat()", v-b-tooltip.hover.bottom="'Reinstate Chat Privileges'")
|
||||
| un-mute
|
||||
span.admin-action(v-if='!hero.auth.blocked',
|
||||
@click="adminBlockUser()", v-b-tooltip.hover.bottom="'Ban User'")
|
||||
| ban
|
||||
span.admin-action(v-if='hero.auth.blocked',
|
||||
@click="adminUnblockUser()", v-b-tooltip.hover.bottom="'Un-Ban User'")
|
||||
| un-ban
|
||||
.row
|
||||
.col-12
|
||||
member-details(:member="user")
|
||||
@@ -152,11 +159,6 @@
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
.gearTitle {
|
||||
color: white;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.progress-container > .progress {
|
||||
background-color: $gray-500 !important;
|
||||
height: 16px !important;
|
||||
@@ -189,6 +191,16 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.admin-profile-actions {
|
||||
margin-bottom: 3em;
|
||||
|
||||
.admin-action {
|
||||
color: blue;
|
||||
cursor: pointer;
|
||||
padding: 0 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-actions {
|
||||
float: right;
|
||||
margin-right: 1em;
|
||||
@@ -329,11 +341,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.gearTitle {
|
||||
color: white;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.profile-section {
|
||||
h2 {
|
||||
overflow: hidden;
|
||||
@@ -596,6 +603,22 @@ export default {
|
||||
openSendGemsModal () {
|
||||
this.$root.$emit('habitica::send-gems', this.user);
|
||||
},
|
||||
adminTurnOnShadowMuting () {
|
||||
if (!this.hero.flags) {
|
||||
this.hero.flags = {};
|
||||
}
|
||||
this.hero.flags.chatShadowMuted = true;
|
||||
|
||||
this.$store.dispatch('hall:updateHero', { heroDetails: this.hero });
|
||||
},
|
||||
adminTurnOffShadowMuting () {
|
||||
if (!this.hero.flags) {
|
||||
this.hero.flags = {};
|
||||
}
|
||||
this.hero.flags.chatShadowMuted = false;
|
||||
|
||||
this.$store.dispatch('hall:updateHero', { heroDetails: this.hero });
|
||||
},
|
||||
adminRevokeChat () {
|
||||
if (!this.hero.flags) {
|
||||
this.hero.flags = {};
|
||||
@@ -622,9 +645,13 @@ export default {
|
||||
|
||||
this.$store.dispatch('hall:updateHero', { heroDetails: this.hero });
|
||||
},
|
||||
async loadAdminTools () {
|
||||
this.hero = await this.$store.dispatch('hall:getHero', { uuid: this.user._id });
|
||||
this.adminToolsLoaded = true;
|
||||
async toggleAdminTools () {
|
||||
if (this.adminToolsLoaded) {
|
||||
this.adminToolsLoaded = false;
|
||||
} else {
|
||||
this.hero = await this.$store.dispatch('hall:getHero', { uuid: this.user._id });
|
||||
this.adminToolsLoaded = true;
|
||||
}
|
||||
},
|
||||
showAllocation () {
|
||||
return this.user._id === this.userLoggedIn._id && this.hasClass;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
:placement="'bottom'",
|
||||
:preventOverflow="false",
|
||||
)
|
||||
h4.gearTitle {{ getGearTitle(equippedItems[key]) }}
|
||||
h4.popover-title-only {{ getGearTitle(equippedItems[key]) }}
|
||||
attributesGrid.attributesGrid(
|
||||
:item="content.gear.flat[equippedItems[key]]",
|
||||
:user="user"
|
||||
@@ -49,7 +49,7 @@
|
||||
:placement="'bottom'",
|
||||
:preventOverflow="false",
|
||||
)
|
||||
h4.gearTitle {{ getGearTitle(costumeItems[key]) }}
|
||||
h4.popover-title-only {{ getGearTitle(costumeItems[key]) }}
|
||||
attributesGrid.attributesGrid(
|
||||
:item="content.gear.flat[costumeItems[key]]",
|
||||
:user="user"
|
||||
|
||||
@@ -32,5 +32,15 @@ export default {
|
||||
|
||||
this.$root.$emit('buyModal::boughtItem', item);
|
||||
},
|
||||
confirmPurchase (currency, cost) {
|
||||
const currencyToPurchaseForKey = {
|
||||
gems: 'purchaseFor',
|
||||
gold: 'purchaseForGold',
|
||||
hourglasses: 'purchaseForHourglasses',
|
||||
};
|
||||
|
||||
const purchaseForKey = currencyToPurchaseForKey[currency];
|
||||
return confirm(this.$t(purchaseForKey, { cost }));
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"backgroundCloudsText": "Skyer",
|
||||
"backgroundCloudsNotes": "Svæve gennem skyerne.",
|
||||
"backgroundDustyCanyonsText": "Støvet Bjergkløft",
|
||||
"backgroundDustyCanyonsNotes": "Gå gennem en Støvet Bjergkløft",
|
||||
"backgroundDustyCanyonsNotes": "Gå gennem en Støvet Bjergkløft.",
|
||||
"backgroundVolcanoText": "Vulkan",
|
||||
"backgroundVolcanoNotes": "Varm op indeni en vulkan.",
|
||||
"backgrounds092014": "SÆT 4: Udgivet September 2014",
|
||||
@@ -83,30 +83,30 @@
|
||||
"backgroundGumdropLandNotes": "Nyd udsigten i Vingummiland - nam nam!",
|
||||
"backgrounds052015": "Sæt 12: Udgivet Maj 2015",
|
||||
"backgroundMarbleTempleText": "Marmortempel",
|
||||
"backgroundMarbleTempleNotes": "Posér foran et Marmortempel",
|
||||
"backgroundMarbleTempleNotes": "Posér foran et Marmortempel.",
|
||||
"backgroundMountainLakeText": "Bjergsø",
|
||||
"backgroundMountainLakeNotes": "Dyp dine tæer i en Bjergsø",
|
||||
"backgroundMountainLakeNotes": "Dyp dine tæer i en Bjergsø.",
|
||||
"backgroundPagodasText": "Pagoder",
|
||||
"backgroundPagodasNotes": "Kravl op på toppen af Pagoder.",
|
||||
"backgrounds062015": "SÆT 13: Udgivet Juni 2015",
|
||||
"backgroundDriftingRaftText": "Tømmerflåde",
|
||||
"backgroundDriftingRaftNotes": "Sejl på en Tømmerflåde",
|
||||
"backgroundDriftingRaftNotes": "Sejl på en Tømmerflåde.",
|
||||
"backgroundShimmeryBubblesText": "Skinnende Bobler",
|
||||
"backgroundShimmeryBubblesNotes": "Flyd gennem et hav af Skinnende Bobler",
|
||||
"backgroundShimmeryBubblesNotes": "Flyd gennem et hav af Skinnende Bobler.",
|
||||
"backgroundIslandWaterfallsText": "Øens Vandfald",
|
||||
"backgroundIslandWaterfallsNotes": "Tag på skovtur nær Øens Vandfald",
|
||||
"backgroundIslandWaterfallsNotes": "Tag på skovtur nær Øens Vandfald.",
|
||||
"backgrounds072015": "Sæt 14: Udgivet Juli 2015",
|
||||
"backgroundDilatoryRuinsText": "Forhalingens Ruiner",
|
||||
"backgroundDilatoryRuinsNotes": "Dyk ned i Forhalingens Ruiner",
|
||||
"backgroundDilatoryRuinsNotes": "Dyk ned i Forhalingens Ruiner.",
|
||||
"backgroundGiantWaveText": "Kæmpe Bølge",
|
||||
"backgroundGiantWaveNotes": "Surf en Kæmpe Bølge!",
|
||||
"backgroundSunkenShipText": "Sunket Skib",
|
||||
"backgroundSunkenShipNotes": "Udforsk et Sunket Skib",
|
||||
"backgroundSunkenShipNotes": "Udforsk et Sunket Skib.",
|
||||
"backgrounds082015": "Sæt 15: Udgivet August 2015",
|
||||
"backgroundPyramidsText": "Pyramider",
|
||||
"backgroundPyramidsNotes": "Nyd synet af Pyramiderne",
|
||||
"backgroundPyramidsNotes": "Nyd synet af Pyramiderne.",
|
||||
"backgroundSunsetSavannahText": "Solnedgang over Savannen",
|
||||
"backgroundSunsetSavannahNotes": "Gå en tur på savannen i solnedgangen",
|
||||
"backgroundSunsetSavannahNotes": "Gå en tur på Savannen i Solnedgangen.",
|
||||
"backgroundTwinklyPartyLightsText": "Blinkende Festlys",
|
||||
"backgroundTwinklyPartyLightsNotes": "Dans under de blinkende festlys!",
|
||||
"backgrounds092015": "SÆT 16: Udgivet September 2015",
|
||||
@@ -143,7 +143,7 @@
|
||||
"backgroundSnowmanArmyText": "Snemandshær",
|
||||
"backgroundSnowmanArmyNotes": "Led en Snemandshær.",
|
||||
"backgroundWinterNightText": "Vinternat",
|
||||
"backgroundWinterNightNotes": "Se på Vinternattens stjerne",
|
||||
"backgroundWinterNightNotes": "Se på Vinternattens stjerner.",
|
||||
"backgrounds022016": "SÆT 21: Udgivet Februar2016",
|
||||
"backgroundBambooForestText": "Bambusskov",
|
||||
"backgroundBambooForestNotes": "Spadser gennem bambusskoven.",
|
||||
@@ -178,14 +178,14 @@
|
||||
"backgroundLilypadText": "Åkande",
|
||||
"backgroundLilypadNotes": "Hop på en Åkande.",
|
||||
"backgroundWaterfallRockText": "vandfald sten",
|
||||
"backgroundWaterfallRockNotes": "lander på et vandfald sten",
|
||||
"backgroundWaterfallRockNotes": "Plask rundt ved Vandfaldsstenen.",
|
||||
"backgrounds072016": "SÆT 26: Udgivet juli 2016",
|
||||
"backgroundAquariumText": "Akvarium",
|
||||
"backgroundAquariumNotes": "Bide efter æbler i et Akvarium.",
|
||||
"backgroundDeepSeaText": "Dybe Ocean",
|
||||
"backgroundDeepSeaNotes": "Dyk ned i det Dybe Ocean.",
|
||||
"backgroundDilatoryCastleText": "Forhalingernes Slot",
|
||||
"backgroundDilatoryCastleNotes": "Svøm forbi Forhalingernes Slot",
|
||||
"backgroundDilatoryCastleNotes": "Svøm forbi Forhalingernes Slot.",
|
||||
"backgrounds082016": "Sæt 27: Udgivet August 2016",
|
||||
"backgroundIdyllicCabinText": "Idyllisk Hytte",
|
||||
"backgroundIdyllicCabinNotes": "Trække dig tilbage til en Idyllisk Hytte.",
|
||||
@@ -229,18 +229,18 @@
|
||||
"backgroundYellowNotes": "En graciøs gul baggrund.",
|
||||
"backgrounds122016": "SÆT 31: Udgivet December 2016",
|
||||
"backgroundShimmeringIcePrismText": "Glimtende Is Prismer",
|
||||
"backgroundShimmeringIcePrismNotes": "Dans gennem de Glimetende Is Prismer",
|
||||
"backgroundShimmeringIcePrismNotes": "Dans gennem de Glimtende Isprismer.",
|
||||
"backgroundWinterFireworksText": "Vinter Fyrværkeri",
|
||||
"backgroundWinterFireworksNotes": "Sæt af Vinter Fyrværkeri.",
|
||||
"backgroundWinterStorefrontText": "Vinter Marked",
|
||||
"backgroundWinterStorefrontNotes": "Køb gaver fra et Vinter Marked",
|
||||
"backgroundWinterStorefrontNotes": "Køb gaver fra et Vintermarked.",
|
||||
"backgrounds012017": "Sæt 32: Udgivet Januar 2017",
|
||||
"backgroundBlizzardText": "Snestorm",
|
||||
"backgroundBlizzardNotes": "Kæmp dig modigt igennem en voldsom Snestorm.",
|
||||
"backgroundSparklingSnowflakeText": "Glitrende Snefnug",
|
||||
"backgroundSparklingSnowflakeNotes": "Glid på et Glitrende Snefnug",
|
||||
"backgroundSparklingSnowflakeNotes": "Glid på et Glitrende Snefnug.",
|
||||
"backgroundStoikalmVolcanoesText": "Stoïkalm Vulkaner",
|
||||
"backgroundStoikalmVolcanoesNotes": "Udforsk Stoïkalm Vulkaner",
|
||||
"backgroundStoikalmVolcanoesNotes": "Udforsk Stoïkalm Vulkaner.",
|
||||
"backgrounds022017": "Sæt 33: Udgivet Februar 2017",
|
||||
"backgroundBellTowerText": "Klokketårn",
|
||||
"backgroundBellTowerNotes": "Kravl op til Klokketårnet.",
|
||||
@@ -263,7 +263,7 @@
|
||||
"backgroundMistShroudedMountainText": "Tåge-Indhyllet Bjerg",
|
||||
"backgroundMistShroudedMountainNotes": "Bestig et Tåge-Indhyllet Bjerg.",
|
||||
"backgrounds052017": "SÆT 36: Udgivet Maj 2017",
|
||||
"backgroundGuardianStatuesText": "Beskytter Statuer ",
|
||||
"backgroundGuardianStatuesText": "Vogterstatuer",
|
||||
"backgroundGuardianStatuesNotes": "Stå vagt foran Beskytter Statuer.",
|
||||
"backgroundHabitCityStreetsText": "Habit City Gader",
|
||||
"backgroundHabitCityStreetsNotes": "Udforsk gaderne i Habit City.",
|
||||
@@ -288,13 +288,13 @@
|
||||
"backgroundBackOfGiantBeastNotes": "Rid på Ryggen af et Kæmpe Dyr.",
|
||||
"backgroundDesertDunesText": "Ørken Klitter",
|
||||
"backgroundDesertDunesNotes": "Udforsk dristigt Ørken Klitterne.",
|
||||
"backgroundSummerFireworksText": "Sommer Fyrværkeri ",
|
||||
"backgroundSummerFireworksText": "Sommerfyrværkeri",
|
||||
"backgroundSummerFireworksNotes": "Fejr Habiticas navnedag med sommerfyrværkeri!",
|
||||
"backgrounds092017": "SÆT 40: Udgivet September 2017",
|
||||
"backgroundBesideWellText": "Ved siden af en Brønd",
|
||||
"backgroundBesideWellNotes": "Gå ved siden af en Brønd.",
|
||||
"backgroundGardenShedText": "Haveskur",
|
||||
"backgroundGardenShedNotes": "Arbejd i et haveskur",
|
||||
"backgroundGardenShedNotes": "Arbejd i et Haveskur.",
|
||||
"backgroundPixelistsWorkshopText": "Pixelistens Workshop",
|
||||
"backgroundPixelistsWorkshopNotes": "Skab et mesterværk i Pixelistens Workshop.",
|
||||
"backgrounds102017": "SÆT 41: Udgivet oktober 2017",
|
||||
@@ -306,14 +306,14 @@
|
||||
"backgroundTarPitsNotes": "Trippe gennem Tjæresøerne.",
|
||||
"backgrounds112017": "Sæt 42: Udgivet november 2017",
|
||||
"backgroundFiberArtsRoomText": "Fiberkunstsrum",
|
||||
"backgroundFiberArtsRoomNotes": "Spind tråd i fiberkunstsrummet",
|
||||
"backgroundFiberArtsRoomNotes": "Spind tråd i Fiberkunstrummet.",
|
||||
"backgroundMidnightCastleText": "Midnatsslottet",
|
||||
"backgroundMidnightCastleNotes": "Spadsere forbi Midnatsslottet.",
|
||||
"backgroundTornadoText": "Tornado",
|
||||
"backgroundTornadoNotes": "Flyve igennem en tornado.",
|
||||
"backgrounds122017": "SÆT 43: Udgivet December 2017",
|
||||
"backgroundCrosscountrySkiTrailText": "Cross-Langrendsløjpe",
|
||||
"backgroundCrosscountrySkiTrailNotes": "Glide langs en Cross-Langrendsløjpe",
|
||||
"backgroundCrosscountrySkiTrailNotes": "Glid langs en Cross-Langrendssløjpe.",
|
||||
"backgroundStarryWinterNightText": "Stjernerig vinternat",
|
||||
"backgroundStarryWinterNightNotes": "Beundre en stjernerig vinternat.",
|
||||
"backgroundToymakersWorkshopText": "Legetøjsmagerens værksted",
|
||||
@@ -324,89 +324,110 @@
|
||||
"backgroundDrivingASleighText": "Slæde",
|
||||
"backgroundDrivingASleighNotes": "Kør en slæde over snebedækkede landskaber.",
|
||||
"backgroundFlyingOverIcySteppesText": "Glatte trin",
|
||||
"backgroundFlyingOverIcySteppesNotes": "Flyv over glatte trin",
|
||||
"backgroundFlyingOverIcySteppesNotes": "Flyv over Isstepperne.",
|
||||
"backgrounds022018": "SÆT 45: Udgivet Februar 2018",
|
||||
"backgroundChessboardLandText": "Skakbrætsland",
|
||||
"backgroundChessboardLandNotes": "Spil et spil i skakbrækkets land",
|
||||
"backgroundChessboardLandNotes": "Spil et spil i Skakbrækkets land.",
|
||||
"backgroundMagicalMuseumText": "Magisk museum",
|
||||
"backgroundMagicalMuseumNotes": "Tag rundtur på et magisk museum",
|
||||
"backgroundMagicalMuseumNotes": "Tag en rundtur på et Magisk Museum.",
|
||||
"backgroundRoseGardenText": "Rosenhave",
|
||||
"backgroundRoseGardenNotes": "Drys i en duftende rosenhave",
|
||||
"backgrounds032018": "SET 46: Released March 2018",
|
||||
"backgroundRoseGardenNotes": "Drys i en duftende Rosenhave.",
|
||||
"backgrounds032018": "SÆT 46: Frigjort marts 2018",
|
||||
"backgroundGorgeousGreenhouseText": "Vidunderligt drivhus",
|
||||
"backgroundGorgeousGreenhouseNotes": "Gå blandt blomsterne i et vidunderlig drivhus.",
|
||||
"backgroundElegantBalconyText": "Elegant balkon",
|
||||
"backgroundElegantBalconyNotes": "Sku over landskabet fra en elegant balkon.",
|
||||
"backgroundDrivingACoachText": "Driving a Coach",
|
||||
"backgroundDrivingACoachNotes": "Enjoy Driving a Coach past fields of flowers.",
|
||||
"backgrounds042018": "SET 47: Released April 2018",
|
||||
"backgroundTulipGardenText": "Tulip Garden",
|
||||
"backgroundTulipGardenNotes": "Tiptoe through a Tulip Garden.",
|
||||
"backgroundFlyingOverWildflowerFieldText": "Field of Wildflowers",
|
||||
"backgroundFlyingOverWildflowerFieldNotes": "Soar above a Field of Wildflowers.",
|
||||
"backgroundDrivingACoachText": "Kør en Karet",
|
||||
"backgroundDrivingACoachNotes": "Nyd en Køretur i karet forbi blomstrende enge.",
|
||||
"backgrounds042018": "SÆT 47: Frigjort april 2018",
|
||||
"backgroundTulipGardenText": "Tulipanhave",
|
||||
"backgroundTulipGardenNotes": "List gennem en Tulipanhave.",
|
||||
"backgroundFlyingOverWildflowerFieldText": "Eng med vilde blomster",
|
||||
"backgroundFlyingOverWildflowerFieldNotes": "Svæv over en Eng med vilde blomster.",
|
||||
"backgroundFlyingOverAncientForestText": "Ancient Forest",
|
||||
"backgroundFlyingOverAncientForestNotes": "Fly over the canopy of an Ancient Forest.",
|
||||
"backgrounds052018": "SET 48: Released May 2018",
|
||||
"backgroundTerracedRiceFieldText": "Terraced Rice Field",
|
||||
"backgroundTerracedRiceFieldNotes": "Enjoy a Terraced Rice Field in the growing season.",
|
||||
"backgroundFantasticalShoeStoreText": "Fantastical Shoe Store",
|
||||
"backgroundFantasticalShoeStoreNotes": "Look for fun new footwear in the Fantastical Shoe Store.",
|
||||
"backgroundChampionsColosseumText": "Champions' Colosseum",
|
||||
"backgroundChampionsColosseumNotes": "Bask in the glory of the Champions' Colosseum.",
|
||||
"backgrounds062018": "SET 49: Released June 2018",
|
||||
"backgroundDocksText": "Docks",
|
||||
"backgroundDocksNotes": "Fish from atop the Docks.",
|
||||
"backgroundRowboatText": "Rowboat",
|
||||
"backgroundRowboatNotes": "Sing rounds in a Rowboat.",
|
||||
"backgroundPirateFlagText": "Pirate Flag",
|
||||
"backgroundPirateFlagNotes": "Fly a fearsome Pirate Flag.",
|
||||
"backgrounds072018": "SET 50: Released July 2018",
|
||||
"backgroundDarkDeepText": "Dark Deep",
|
||||
"backgroundDarkDeepNotes": "Swim in the Dark Deep among bioluminescent critters.",
|
||||
"backgroundDilatoryCityText": "City of Dilatory",
|
||||
"backgroundDilatoryCityNotes": "Meander through the undersea City of Dilatory.",
|
||||
"backgroundTidePoolText": "Tide Pool",
|
||||
"backgroundTidePoolNotes": "Observe the ocean life near a Tide Pool.",
|
||||
"backgrounds082018": "SET 51: Released August 2018",
|
||||
"backgroundTrainingGroundsText": "Training Grounds",
|
||||
"backgroundTrainingGroundsNotes": "Spar on the Training Grounds.",
|
||||
"backgroundFlyingOverRockyCanyonText": "Rocky Canyon",
|
||||
"backgroundFlyingOverRockyCanyonNotes": "Look down into a breathtaking scene as you fly over a Rocky Canyon.",
|
||||
"backgroundBridgeText": "Bridge",
|
||||
"backgroundBridgeNotes": "Cross a charming Bridge.",
|
||||
"backgrounds092018": "SET 52: Released September 2018",
|
||||
"backgroundApplePickingText": "Apple Picking",
|
||||
"backgroundApplePickingNotes": "Go Apple Picking and bring home a bushel.",
|
||||
"backgroundGiantBookText": "Giant Book",
|
||||
"backgroundGiantBookNotes": "Read as you walk through the pages of a Giant Book.",
|
||||
"backgroundCozyBarnText": "Cozy Barn",
|
||||
"backgroundCozyBarnNotes": "Relax with your pets and mounts in their Cozy Barn.",
|
||||
"backgrounds102018": "SET 53: Released October 2018",
|
||||
"backgroundBayouText": "Bayou",
|
||||
"backgroundBayouNotes": "Bask in the fireflies' glow on the misty Bayou.",
|
||||
"backgroundCreepyCastleText": "Creepy Castle",
|
||||
"backgroundCreepyCastleNotes": "Dare to approach a Creepy Castle.",
|
||||
"backgroundDungeonText": "Dungeon",
|
||||
"backgroundDungeonNotes": "Rescue the prisoners of a spooky Dungeon.",
|
||||
"backgrounds112018": "SET 54: Released November 2018",
|
||||
"backgroundBackAlleyText": "Back Alley",
|
||||
"backgroundBackAlleyNotes": "Look shady loitering in a Back Alley.",
|
||||
"backgroundGlowingMushroomCaveText": "Glowing Mushroom Cave",
|
||||
"backgroundGlowingMushroomCaveNotes": "Stare in awe at a Glowing Mushroom Cave.",
|
||||
"backgroundCozyBedroomText": "Cozy Bedroom",
|
||||
"backgroundCozyBedroomNotes": "Curl up in a Cozy Bedroom.",
|
||||
"backgrounds122018": "SET 55: Released December 2018",
|
||||
"backgroundFlyingOverSnowyMountainsText": "Snowy Mountains",
|
||||
"backgroundFlyingOverSnowyMountainsNotes": "Soar over Snowy Mountains at night.",
|
||||
"backgroundFrostyForestText": "Frosty Forest",
|
||||
"backgroundFrostyForestNotes": "Bundle up to hike through a Frosty Forest.",
|
||||
"backgroundSnowyDayFireplaceText": "Snowy Day Fireplace",
|
||||
"backgroundSnowyDayFireplaceNotes": "Snuggle up next to a Fireplace on a Snowy Day.",
|
||||
"backgrounds012019": "SET 56: Released January 2019",
|
||||
"backgroundAvalancheText": "Avalanche",
|
||||
"backgroundAvalancheNotes": "Flee the thundering might of an Avalanche.",
|
||||
"backgroundArchaeologicalDigText": "Archaeological Dig",
|
||||
"backgroundArchaeologicalDigNotes": "Unearth secrets of the ancient past at an Archaeological Dig.",
|
||||
"backgroundScribesWorkshopText": "Scribe's Workshop",
|
||||
"backgroundScribesWorkshopNotes": "Write your next great scroll in a Scribe's Workshop."
|
||||
}
|
||||
"backgroundFlyingOverAncientForestNotes": "Flyv over trækronen af en Oldgammel skov.",
|
||||
"backgrounds052018": "SÆT 48: Frigjort maj 2018",
|
||||
"backgroundTerracedRiceFieldText": "Terrassemark",
|
||||
"backgroundTerracedRiceFieldNotes": "Nyd en Terrassemark midt i risdyrkningssæsonen.",
|
||||
"backgroundFantasticalShoeStoreText": "Fantastisk skobutik",
|
||||
"backgroundFantasticalShoeStoreNotes": "Kig efter nyt, sjovt fodtøj i den Fantastiske skobutik.",
|
||||
"backgroundChampionsColosseumText": "Mestrenes Colosseum",
|
||||
"backgroundChampionsColosseumNotes": "Lad æren af Mestrenes Colosseum skinne på dig.",
|
||||
"backgrounds062018": "SÆT 49: Frigjort juni 2018",
|
||||
"backgroundDocksText": "Kajen",
|
||||
"backgroundDocksNotes": "Fisk fra Kajen.",
|
||||
"backgroundRowboatText": "Robåd",
|
||||
"backgroundRowboatNotes": "Syng rundesang i en Robåd.",
|
||||
"backgroundPirateFlagText": "Piratflag",
|
||||
"backgroundPirateFlagNotes": "Hejs et frygtindgydende Piratflag.",
|
||||
"backgrounds072018": "SÆT 50: Frigjort juli 2018",
|
||||
"backgroundDarkDeepText": "Det mørke dyb",
|
||||
"backgroundDarkDeepNotes": "Svøm i Det mørke dyb blandt naturligt lysende smådyr.",
|
||||
"backgroundDilatoryCityText": "Forhalingens by",
|
||||
"backgroundDilatoryCityNotes": "Spadser gennem Forhalingens by under vandet.",
|
||||
"backgroundTidePoolText": "Tidevandspøl",
|
||||
"backgroundTidePoolNotes": "Observer havlivet nær en Tidevandspøl.",
|
||||
"backgrounds082018": "SÆT 51: Frigjort august 2018",
|
||||
"backgroundTrainingGroundsText": "Træningspladsen",
|
||||
"backgroundTrainingGroundsNotes": "Spar på Træningspladsen.",
|
||||
"backgroundFlyingOverRockyCanyonText": "Stenet kløft",
|
||||
"backgroundFlyingOverRockyCanyonNotes": "Se ned på et betagende vue mens du flyver over en Stenet kløft.",
|
||||
"backgroundBridgeText": "Bro",
|
||||
"backgroundBridgeNotes": "Kryds en charmerende Bro.",
|
||||
"backgrounds092018": "SÆT 52: Frigjort september 2018",
|
||||
"backgroundApplePickingText": "Æbleplukning",
|
||||
"backgroundApplePickingNotes": "Tag på Æblepluk og tag en skæppe med hjem.",
|
||||
"backgroundGiantBookText": "Kæmpe bog",
|
||||
"backgroundGiantBookNotes": "Læs, mens du går over siderne på en Kæmpe bog.",
|
||||
"backgroundCozyBarnText": "Hyggelig lade",
|
||||
"backgroundCozyBarnNotes": "Slap af med dine kæle- og ridedyr i deres Hyggelige lade.",
|
||||
"backgrounds102018": "SÆT 53: Frigjort oktober 2018",
|
||||
"backgroundBayouText": "Marsk",
|
||||
"backgroundBayouNotes": "Nyd ildfluernes glød i den tågede Marsk.",
|
||||
"backgroundCreepyCastleText": "Skummelt slot",
|
||||
"backgroundCreepyCastleNotes": "Tør du nærme dig det Skumle Slot?",
|
||||
"backgroundDungeonText": "Fangehul",
|
||||
"backgroundDungeonNotes": "Red fangerne fra det uhyggelige Fangehul.",
|
||||
"backgrounds112018": "SÆT 54: Frigjort november 2018",
|
||||
"backgroundBackAlleyText": "Gyde",
|
||||
"backgroundBackAlleyNotes": "Se skummel ud, mens du hænger i en Gyde.",
|
||||
"backgroundGlowingMushroomCaveText": "Lysende svampegrotte",
|
||||
"backgroundGlowingMushroomCaveNotes": "Se dig med ærefrygt omkring i den Lysende svampegrotte.",
|
||||
"backgroundCozyBedroomText": "Hyggeligt soveværelse",
|
||||
"backgroundCozyBedroomNotes": "Krøl dig sammen i et Hyggeligt soveværelse.",
|
||||
"backgrounds122018": "SÆT 55: Frigjort december 2018",
|
||||
"backgroundFlyingOverSnowyMountainsText": "Sneklædte bjerge",
|
||||
"backgroundFlyingOverSnowyMountainsNotes": "Svæv over de Sneklædte bjerge om natten.",
|
||||
"backgroundFrostyForestText": "Frossen skov",
|
||||
"backgroundFrostyForestNotes": "Klæd dig varmt på og tag en gåtur gennem en Frossen skov.",
|
||||
"backgroundSnowyDayFireplaceText": "Ildsted på en snevejrsdag",
|
||||
"backgroundSnowyDayFireplaceNotes": "Lun dig ved Ildstedet på en snevejrsdag.",
|
||||
"backgrounds012019": "SÆT 56: Frigjort januar 2019",
|
||||
"backgroundAvalancheText": "Lavine",
|
||||
"backgroundAvalancheNotes": "Flygt fra en tordnende Lavine.",
|
||||
"backgroundArchaeologicalDigText": "Arkæologisk udgravning",
|
||||
"backgroundArchaeologicalDigNotes": "Få oldtidens hemmeligheder frem i lyset ved den Arkæologiske udgravning.",
|
||||
"backgroundScribesWorkshopText": "Den skriftkloges arbejdsværelse",
|
||||
"backgroundScribesWorkshopNotes": "Skriv din næste utrolige skriftrulle i Den skriftkloges arbejdsværelse.",
|
||||
"backgrounds022019": "SÆT 57: Frigjort februar 2019",
|
||||
"backgroundMedievalKitchenText": "Middelalderligt køkken",
|
||||
"backgroundMedievalKitchenNotes": "Lav magisk mad i et Middelalderligt køkken.",
|
||||
"backgroundOldFashionedBakeryText": "Gammeldags bageri",
|
||||
"backgroundOldFashionedBakeryNotes": "Nyd de liflige dufte uden for et Gammeldags bageri.",
|
||||
"backgroundValentinesDayFeastingHallText": "Festhal til Valentinsdag",
|
||||
"backgroundValentinesDayFeastingHallNotes": "Mærk kærligheden i Festhallen til Valentinsdag.",
|
||||
"backgrounds032019": "SÆT 58: Frigjort marts 2019",
|
||||
"backgroundDuckPondText": "Andedam",
|
||||
"backgroundDuckPondNotes": "Fodr vandfugle ved Andedammen.",
|
||||
"backgroundFieldWithColoredEggsText": "Eng med farvede æg",
|
||||
"backgroundFieldWithColoredEggsNotes": "Led efter en forårsskat i en Eng med farvede æg.",
|
||||
"backgroundFlowerMarketText": "Blomstermarked",
|
||||
"backgroundFlowerMarketNotes": "Find de perfekte farver til en buket eller have på Blomstermarkedet.",
|
||||
"backgrounds042019": "SÆT 59: Frigjort april 2019",
|
||||
"backgroundBirchForestText": "Birkeskov",
|
||||
"backgroundBirchForestNotes": "Tul rundt i en fredfyldt Birkeskov.",
|
||||
"backgroundHalflingsHouseText": "Halvlingehus",
|
||||
"backgroundHalflingsHouseNotes": "Besøg et charmerende Halvlingehus.",
|
||||
"backgroundBlossomingDesertText": "Blomstrende ørken",
|
||||
"backgroundBlossomingDesertNotes": "Vær vidne til en sjælden superblomstring i den Blomstrende ørken."
|
||||
}
|
||||
|
||||