Compare commits
615 Commits
migrate/vu
...
develop
Author | SHA1 | Date |
---|---|---|
HJ | 82db31f7ac | |
HJ | 5810f6f431 | |
HJ | 8b07d0201e | |
HJ | fd1011f622 | |
Henry Jameson | eb27f1205b | |
Henry Jameson | daa39b6e8f | |
HJ | 3e99006e2a | |
HJ | e232ba0ec5 | |
HJ | 3128ea57e1 | |
Phantasm | 564cc73d31 | |
HJ | 9d2572ffdb | |
HJ | a4264b9cd2 | |
HJ | 51709ad318 | |
marcin mikołajczak | 4de9daa114 | |
Phantasm | b19749c320 | |
HJ | 3056017f8e | |
HJ | 36f2fef55a | |
Henry Jameson | 6ff0a7f021 | |
Henry Jameson | 6473260487 | |
Henry Jameson | 046678086f | |
Alexander Tumin | 59656af44c | |
Henry Jameson | 6ea69eb51a | |
Henry Jameson | c40b02ac2f | |
Henry Jameson | af236d71f0 | |
Henry Jameson | 5505a89e8a | |
Henry Jameson | b2e10ac8c1 | |
HJ | 15dde2d372 | |
HJ | 2cbfcb6a6d | |
HJ | e853d746b0 | |
SyoBoN | 2ede1f669a | |
HJ | 09313a9fcd | |
marcin mikołajczak | 1ceffb4e71 | |
tusooa | b173741f87 | |
tusooa | 39269c4829 | |
Gllm R | 3d025eb7bf | |
Gllm R | d6ef47f1c3 | |
jammer lammer | 82af61f5b4 | |
Phantasm | eb03844387 | |
Phantasm | b610caeca8 | |
Phantasm | 9b65c30c12 | |
Phantasm | 1b667fbb01 | |
HJ | 0635a6c131 | |
Henry Jameson | 3eabdf9ded | |
Henry Jameson | ece159822c | |
Henry Jameson | c0010d0f48 | |
Henry Jameson | 8ead084421 | |
Henry Jameson | 19ab07af96 | |
Henry Jameson | 1c23a16bac | |
Henry Jameson | 9806eea12e | |
Henry Jameson | e8159164e3 | |
Henry Jameson | dd4867d8de | |
Henry Jameson | 2382810823 | |
Henry Jameson | fbea4f9986 | |
Henry Jameson | 940df1efa7 | |
Henry Jameson | 9bdc8d9b9c | |
Phantasm | d5575f9c13 | |
HJ | d7f744d281 | |
Henry Jameson | c298611af2 | |
Henry Jameson | 300b3a2517 | |
Henry Jameson | def68e9cda | |
Henry Jameson | 4c10cf21a0 | |
Henry Jameson | f3d3901a92 | |
Henry Jameson | c1568ad2ba | |
Henry Jameson | 1050fed558 | |
Henry Jameson | e51278cdf1 | |
Henry Jameson | b925c32e67 | |
Henry Jameson | 46562d5318 | |
Henry Jameson | 4852f5b833 | |
Henry Jameson | d02a15043e | |
HJ | 23edfe7b91 | |
HJ | 698d608591 | |
Pleroma Renovate Bot | fa7f6955a1 | |
HJ | 6147f71977 | |
Pleroma Renovate Bot | 69a8ab7a03 | |
HJ | 90082a0d04 | |
HJ | c0961a4420 | |
HJ | b252af872f | |
HJ | 539deb607f | |
HJ | 7e05be9251 | |
HJ | 255512938c | |
HJ | 09da683d28 | |
HJ | d8c50854b7 | |
Pleroma Renovate Bot | 0daa824ec1 | |
Henry Jameson | 472aad52e1 | |
tusooa | 7ee55da4a3 | |
Henry Jameson | 1e467ac6e1 | |
Henry Jameson | afc94c6801 | |
Henry Jameson | 34f23b992e | |
Henry Jameson | 6d77bc2bd5 | |
Henry Jameson | ce5552ae3c | |
Henry Jameson | 1b391b6a69 | |
Henry Jameson | 7d1e787f55 | |
Henry Jameson | 7df207c9d4 | |
Henry Jameson | 962bce5ee3 | |
Kian-ting Tan | e96487ffd5 | |
SyoBoN | 016c69e466 | |
Phantasm | 9c2046e6a7 | |
Phantasm | e22f571874 | |
SyoBoN | a104098467 | |
SyoBoN | c29c524033 | |
Phantasm | 40fa9b6ae4 | |
HJ | 943fee9fbc | |
Henry Jameson | 3239bd34df | |
Henry Jameson | 7f38d7d474 | |
Henry Jameson | e4f2741989 | |
Henry Jameson | dc631c68fd | |
Henry Jameson | b10458e3a3 | |
Henry Jameson | 8d99e2138a | |
Henry Jameson | 7b1f70468b | |
Henry Jameson | 5637e29d9c | |
Henry Jameson | f7cd801e69 | |
Henry Jameson | 7e01d2083d | |
Henry Jameson | 075f2cb903 | |
Henry Jameson | 50a9c077fb | |
Henry Jameson | 7238b218f9 | |
Henry Jameson | 545c875a85 | |
Henry Jameson | a190389f3c | |
Pleroma Renovate Bot | e91e12b4b6 | |
HJ | db33d58ba7 | |
Henry Jameson | 45a4b204c8 | |
HJ | 0f2c5fd972 | |
Henry Jameson | a2f2a0e409 | |
Henry Jameson | 01f6f89c7d | |
Henry Jameson | 23a8bee053 | |
Henry Jameson | fb55c98483 | |
Henry Jameson | e7c64e47c4 | |
Henry Jameson | 54e3a99bc7 | |
Henry Jameson | 73f6ecb21e | |
Henry Jameson | 78dcc0423e | |
Henry Jameson | 28c7fac9f0 | |
Henry Jameson | 3f6b9fbf9c | |
Henry Jameson | 7575079da9 | |
Henry Jameson | cf1345caca | |
Henry Jameson | 8e3637c059 | |
Henry Jameson | 39eee4412f | |
Henry Jameson | 528e7e4496 | |
Henry Jameson | 15d8daa7ec | |
Henry Jameson | e2a675e3ae | |
Henry Jameson | fe93717d47 | |
Henry Jameson | f4d48e401a | |
Henry Jameson | ec2afce97e | |
Henry Jameson | e2af986323 | |
Henry Jameson | eab3bfaf0d | |
Henry Jameson | d134b691cc | |
Henry Jameson | c83ddb0b2b | |
Henry Jameson | d3b5f76486 | |
Henry Jameson | d8827932bc | |
Henry Jameson | adc47ad38a | |
Henry Jameson | 9a24d21bbd | |
Henry Jameson | ef2c8f077d | |
Henry Jameson | dc22386599 | |
Henry Jameson | ac85cdac68 | |
Henry Jameson | c4d218cb3e | |
Henry Jameson | 9bbf2e70c2 | |
Henry Jameson | 1640bb61e3 | |
Henry Jameson | 339ae3e95e | |
Henry Jameson | abd1407a0b | |
Henry Jameson | 6536fe229b | |
Henry Jameson | 623a961141 | |
Henry Jameson | 7d2faccd4f | |
Henry Jameson | 779b3dc122 | |
Henry Jameson | 09e0e53ad6 | |
Henry Jameson | 9e66c1184f | |
Henry Jameson | 7f465cfdb1 | |
Henry Jameson | 5e0ba2bcd9 | |
Henry Jameson | 099a2eb27f | |
Henry Jameson | 4785c553ef | |
Henry Jameson | 879f520b75 | |
Henry Jameson | 8a21594dbc | |
Henry Jameson | 7041d29ede | |
Henry Jameson | d2f4ce442a | |
Henry Jameson | f609aaba0c | |
Henry Jameson | 8a47069cee | |
Henry Jameson | 900eb34186 | |
Henry Jameson | da0db933d9 | |
Henry Jameson | c3e6e7c61d | |
Henry Jameson | 2172529dd0 | |
Henry Jameson | 0285efadbb | |
Henry Jameson | 23dc2d1a5b | |
Henry Jameson | 4a10417ed4 | |
Henry Jameson | 34aa9136db | |
Henry Jameson | 11fd220734 | |
Henry Jameson | ab63ec1471 | |
Henry Jameson | 3b520a98ad | |
Henry Jameson | 1bc1a83a1f | |
Henry Jameson | f4bf374509 | |
Henry Jameson | 6811191147 | |
Henry Jameson | f0bbb75df5 | |
Henry Jameson | 13a289ac74 | |
Henry Jameson | 3e198526e6 | |
Pleroma Renovate Bot | 1be1bdfa41 | |
Henry Jameson | 7c77809ff9 | |
Henry Jameson | 96e3a1593a | |
Henry Jameson | 34e4dd0a79 | |
Henry Jameson | c531391e87 | |
Henry Jameson | c16f1d4e35 | |
Henry Jameson | bcc5084409 | |
Henry Jameson | 17b25ef0e0 | |
Henry Jameson | 709ce1611a | |
Henry Jameson | 48f106b438 | |
Henry Jameson | ae345d2c45 | |
Henry Jameson | 1c5f156af0 | |
Henry Jameson | 98f972e557 | |
Henry Jameson | 9ec61d0f0a | |
Henry Jameson | 1af8ca29f3 | |
Henry Jameson | 1cfdde819b | |
Henry Jameson | 79d2184afa | |
Henry Jameson | 6df28cde9d | |
Henry Jameson | a7d771e8c8 | |
Henry Jameson | 1229bbd855 | |
Henry Jameson | 85d55c55e7 | |
Henry Jameson | a9efbd2553 | |
Henry Jameson | d2a74ea1a2 | |
Henry Jameson | c34590c439 | |
Henry Jameson | d4795d2e3c | |
Henry Jameson | 53a4b1f9a6 | |
Pleroma Renovate Bot | 7c8b9610b9 | |
HJ | 303bfa6e39 | |
Ekaterina Vaartis | 70258a2176 | |
SyoBoN | 8562fd2da6 | |
SyoBoN | 062323c0d5 | |
tusooa | 9042792133 | |
Henry Jameson | ff2db7a247 | |
Henry Jameson | 22b32f149d | |
Pleroma Renovate Bot | d8c22a9e42 | |
Henry Jameson | 0729b529d7 | |
Ekaterina Vaartis | d5a5b8e254 | |
Ekaterina Vaartis | 4d7a915154 | |
Ekaterina Vaartis | 8a030d935b | |
marcin mikołajczak | d28e48e9dc | |
marcin mikołajczak | f6d3a66a5b | |
Ekaterina Vaartis | aa49838355 | |
Ekaterina Vaartis | a2133f5283 | |
Henry Jameson | 521d308a6c | |
HJ | b0d0a3faf6 | |
Phantasm | 88a006eb1a | |
marcin mikołajczak | dbe9da0f09 | |
HJ | ae4e360157 | |
tusooa | 9277a0cc0c | |
tusooa | 209c0a8332 | |
tusooa | 82c0044963 | |
tusooa | 9ec61c07ef | |
tusooa | f5b4b5f777 | |
Ekaterina Vaartis | 872dffe51b | |
Ekaterina Vaartis | 4eeb3e5f78 | |
Ekaterina Vaartis | c218f32f6b | |
Ekaterina Vaartis | f8e1d5e3e0 | |
Ekaterina Vaartis | 4451cccb3c | |
Ekaterina Vaartis | 091532d577 | |
marcin mikołajczak | 6c4c8fe51f | |
tusooa | bdf46eca5a | |
SyoBoN | f3cdcaa172 | |
Xnuk Shuman | 3c4eaaab2c | |
nixe neko | f177e0fe24 | |
marcin mikołajczak | 6f452d672f | |
tusooa | 16f326216a | |
tusooa | a709127a3c | |
tusooa | cc4aaccf38 | |
tusooa | fd77270564 | |
tusooa | 4777bec85f | |
tusooa | 0110fd86c2 | |
SyoBoN | b8a036ee64 | |
SyoBoN | 9b0fb0f798 | |
Ekaterina Vaartis | bfdad56b0d | |
Ekaterina Vaartis | f9c85c0c49 | |
HJ | 6391a6a4ea | |
Mark Felder | 5bd8a78a7a | |
HJ | 2b41c1cfe8 | |
Henry Jameson | 55ed65331f | |
Henry Jameson | ff10834f1a | |
Henry Jameson | 5ad8f2cd5c | |
Henry Jameson | 5ee8fc0aea | |
Henry Jameson | 99d04bed2b | |
Henry Jameson | b394392d0d | |
Henry Jameson | febc2aa569 | |
Henry Jameson | 0fd1b26fb6 | |
Henry Jameson | 4e8bb80dbd | |
Henry Jameson | bcdf336242 | |
Pleroma Renovate Bot | 89c94f97f6 | |
HJ | a98e241a81 | |
Yonle | 5eed197c3e | |
HJ | 4a7b49181a | |
Yonle | fb4d43ced2 | |
HJ | 02fff5ddd5 | |
HJ | ce46b97c59 | |
NEETzsche | 730351dcd1 | |
HJ | 358f92adff | |
Kian-ting Tan | 846f9204f2 | |
tusooa | 7b9e3b5c24 | |
HJ | e84e814c20 | |
Henry Jameson | d580433988 | |
HJ | 9cbcd5b5e3 | |
HJ | 83acbf953a | |
Henry Jameson | 6c78b59c99 | |
Henry Jameson | 2cddc138e5 | |
HJ | 55ecb5239a | |
HJ | d21e3d5de2 | |
Henry Jameson | 51f1f05b2d | |
Henry Jameson | b707a14b10 | |
Henry Jameson | c25170d7d9 | |
Henry Jameson | a5f09b7263 | |
Henry Jameson | 33564d8ccc | |
Henry Jameson | 92685e37b6 | |
Henry Jameson | e36548579f | |
Henry Jameson | 37e3a23f2a | |
Henry Jameson | 1931e7c3ba | |
Henry Jameson | 38b6f0a013 | |
Henry Jameson | cdc0959135 | |
Henry Jameson | c0e2ba37c8 | |
Henry Jameson | 072a06fc89 | |
Henry Jameson | d178a56924 | |
Henry Jameson | fd3ad106be | |
Henry Jameson | e3ee3eacca | |
Henry Jameson | 2f90c629b8 | |
Henry Jameson | a564fc1a1f | |
Henry Jameson | 1037a3bb72 | |
Henry Jameson | a190ef2c56 | |
Henry Jameson | 75eea5f2b2 | |
Henry Jameson | c216340001 | |
Henry Jameson | af27e2ca7b | |
Henry Jameson | 388a7ac175 | |
Henry Jameson | f3a859ff9e | |
Henry Jameson | ce17ebd3d0 | |
Henry Jameson | a17defc5ab | |
Henry Jameson | 6ed2cb8f43 | |
Henry Jameson | aad3225d25 | |
Henry Jameson | fffa7a4f4a | |
Henry Jameson | e508ca6a1f | |
Henry Jameson | d9ea160a67 | |
Henry Jameson | ec2937ec1f | |
Henry Jameson | c059f4a7ee | |
HJ | 84e2fa1a5e | |
HJ | 18c0cf1845 | |
tusooa | 5ff14837a7 | |
Henry Jameson | bf49aeb756 | |
tusooa | 82063f34b2 | |
tusooa | 0026b35f66 | |
HJ | 3781f0e3bf | |
HJ | 9ccd013522 | |
HJ | faef2767cd | |
tusooa | b2c5520d33 | |
tusooa | 661d5b6d25 | |
tusooa | c3c233c6fe | |
Dmytro Poltavchenko | 7c1c4237b4 | |
Tirifto | f49f8dba6f | |
Kian-ting Tan | 698a91d345 | |
Kian-ting Tan | 77b68c9c3f | |
Kian-ting Tan | 06bd834a81 | |
Kian-ting Tan | cf483f62fd | |
Kian-ting Tan | 1aa506e0cb | |
Kian-ting Tan | 267f25f4f6 | |
Kian-ting Tan | 910fdb39e4 | |
Kian-ting Tan | 24a70bb231 | |
Kian-ting Tan | dec13e3624 | |
Kian-ting Tan | 17b04a45ea | |
Kian-ting Tan | 7e55fb5579 | |
Tirifto | 08321c2aac | |
Kian-ting Tan | 6f590a311a | |
Kian-ting Tan | 780dd4e135 | |
Kian-ting Tan | 943e0ac3f5 | |
Xnuk Shuman | 975a240b88 | |
Kian-ting Tan | 6690d9fab6 | |
Xnuk Shuman | a4f0c6fc86 | |
HJ | 60cb173b61 | |
Henry Jameson | 55d4ea3643 | |
NEETzsche | 2c9930bd5b | |
Henry Jameson | e0b8ad9f14 | |
Henry Jameson | 77e270ef58 | |
Henry Jameson | f449bfe2f1 | |
Henry Jameson | ce109c38f3 | |
Henry Jameson | b6a4b62058 | |
Henry Jameson | c99390e864 | |
Henry Jameson | f354cef010 | |
HJ | 954d03150f | |
HJ | 42d5d8e433 | |
Henry Jameson | dbf14eee40 | |
Henry Jameson | c8b5b7845d | |
HJ | b6accf9e7f | |
HJ | f685f9021b | |
Henry Jameson | c9fd9ceb75 | |
Henry Jameson | c622b77ddd | |
Henry Jameson | e3bf9a5185 | |
Henry Jameson | 0628aac664 | |
Henry Jameson | 1b7e930b2e | |
Henry Jameson | 73fbe89a4b | |
HJ | 4c11ac9a27 | |
Henry Jameson | 8f87a15069 | |
tusooa | 3c38a79526 | |
Henry Jameson | 765fdbe8ab | |
Henry Jameson | ece79f84a8 | |
Pleroma Renovate Bot | 4beb29918a | |
tusooa | 45470e3355 | |
tusooa | 8801f63720 | |
tusooa | e66b2b18af | |
tusooa | d356841441 | |
tusooa | c05b1b9072 | |
Haelwenn (lanodan) Monnier | 6e5c7bf308 | |
tusooa | 1d679b59a0 | |
tusooa | b167025554 | |
HJ | 3c041b2ba1 | |
HJ | d8d2507303 | |
HJ | cc0a63736a | |
Alexander Tumin | ac78f80194 | |
tusooa | f059c1f314 | |
tusooa | f153c688f6 | |
tusooa | e4ab012f21 | |
tusooa | ff25838479 | |
tusooa | ebee2bda63 | |
tusooa | a2c21e2742 | |
tusooa | c6715b346b | |
tusooa | 50bad0fc68 | |
tusooa | bd60238f01 | |
tusooa | 1c180ace0b | |
tusooa | 7f51ea369e | |
tusooa | c4549f0993 | |
tusooa | 0d6a9e8a64 | |
Alexander Tumin | 9baffbfbde | |
HJ | a1641193b5 | |
tusooa | 0dc2afb826 | |
HJ | e31bf6646b | |
tusooa | 56a74aa392 | |
tusooa | 0b0b1dabdf | |
tusooa | 1b081a9272 | |
tusooa | 35d3b8f27d | |
tusooa | 510392e4ca | |
Kian-ting Tan | 7aac8cd2ee | |
tusooa | a314ad7ccc | |
tusooa | 441eea3683 | |
tusooa | 99cff7e28b | |
tusooa | 63f56cfb27 | |
tusooa | d22079cf73 | |
tusooa | d72486f3e4 | |
Kian-ting Tan | 80ceff95e9 | |
Kian-ting Tan | 1ec9487714 | |
baloo toumi | 4bdc4bc5a9 | |
tusooa | 1c20487494 | |
Kian-ting Tan | d234000fdf | |
Kian-ting Tan | 837dd81d21 | |
baloo toumi | 6413aef1b4 | |
Pleroma Renovate Bot | 067eefdb44 | |
baloo toumi | fc2aca4ddc | |
@t12 | a417867ec7 | |
baloo toumi | 8173a46030 | |
Kian-ting Tan | 6e93fbb96a | |
Poesty Li | 273aeea05e | |
baloo toumi | d6734a1942 | |
Kian-ting Tan | e47328f170 | |
Kian-ting Tan | 75fcf486dc | |
Kian-ting Tan | 927729f128 | |
Kian-ting Tan | 91bddb7218 | |
tusooa | e57a186b23 | |
HJ | c9d07c6202 | |
HJ | 586705ec02 | |
tusooa | 9fa0c05b35 | |
tusooa | bf5bd4235d | |
tusooa | 09402e2537 | |
tusooa | 8cc6b213fb | |
tusooa | d5e9a28c84 | |
Kian-ting Tan | 7ce71d8f82 | |
Kian-ting Tan | e1fff8e064 | |
Kian-ting Tan | b4cf20e7bc | |
Kian-ting Tan | ee01393b5f | |
Kian-ting Tan | cf0d8c9257 | |
Kian-ting Tan | 8897ac5c9b | |
Kian-ting Tan | d722dc165e | |
Kian-ting Tan | d98650e21d | |
Kian-ting Tan | a7aafd0775 | |
Kian-ting Tan | 21093e573c | |
tusooa | 018f83b997 | |
tusooa | 16140c278b | |
tusooa | 96ef76f1d7 | |
baloo toumi | a7705ade88 | |
baloo toumi | 148e8a7170 | |
baloo toumi | 6ff477e124 | |
baloo toumi | 20621c71dc | |
baloo toumi | 5d63833c99 | |
baloo toumi | 66a881db4f | |
HJ | 336a966a52 | |
tusooa | db1643b94e | |
HJ | 7ab5ee9cba | |
tusooa | 4e6af5bd23 | |
HJ | 5b93e4a0de | |
tusooa | 8ba22a2481 | |
HJ | 321a131c20 | |
HJ | 4bc7873e03 | |
HJ | 624af7ed00 | |
Henry Jameson | 0109724a5f | |
Henry Jameson | 10e28f6c1d | |
Henry Jameson | 5e656cc0b4 | |
Henry Jameson | 00b47e1673 | |
tusooa | ae5181d21e | |
baloo toumi | 8e9f0aabba | |
HJ | c730c9b6d0 | |
Henry Jameson | cbd22d52b8 | |
Henry Jameson | b3d0360699 | |
Henry Jameson | ed34b07b3f | |
Henry Jameson | d223683b2e | |
Henry Jameson | 9f77f910b8 | |
Henry Jameson | 3ead21bcc6 | |
Henry Jameson | b72af7d6ae | |
Henry Jameson | 99f85069b8 | |
Pleroma Renovate Bot | 064ff35822 | |
HJ | 4bf085b8fe | |
HJ | 8692453ffd | |
HJ | 8d32f305fd | |
HJ | 0101f67639 | |
baloo toumi | f4d3575804 | |
HJ | 63ee9088b6 | |
HJ | b6cef856f9 | |
tusooa | b82f2a3543 | |
tusooa | dc2ff9b2d2 | |
tusooa | c675130024 | |
tusooa | d3e251665f | |
tusooa | 48ee11fea3 | |
tusooa | 0b2f676e50 | |
tusooa | 8a1074336c | |
tusooa | ed23f51838 | |
tusooa | 6b0d72937e | |
tusooa | 1e597d8b1a | |
baloo toumi | b171d831f2 | |
Pleroma Renovate Bot | b275c9afa6 | |
tusooa | fc1fda50df | |
Tirifto | 762cdc738f | |
Xnuk Shuman | 811adc5b1f | |
Tirifto | 1dd5fa8bb7 | |
Tirifto | 2e5412fbd8 | |
tusooa | d4ea180a39 | |
Pleroma Renovate Bot | ac21bba90c | |
HJ | fca1e0abae | |
tusooa | f5891e950e | |
tusooa | 4b38fc5ffc | |
Henry Jameson | 4664d99af2 | |
Henry Jameson | ad3916027a | |
Henry Jameson | b79f297692 | |
Henry Jameson | 039b6c61a2 | |
Henry Jameson | 09e3735e37 | |
Henry Jameson | 2322646442 | |
Henry Jameson | 0f81239451 | |
Henry Jameson | 05a7e612aa | |
Henry Jameson | b9c69a2272 | |
Henry Jameson | 1935bf6bd4 | |
Pleroma Renovate Bot | 586cdadcec | |
Pleroma Renovate Bot | 73430beb5c | |
Henry Jameson | 6816bc8bad | |
tusooa | 0f730a8524 | |
Pleroma Renovate Bot | 4d75a58bb9 | |
Pleroma Renovate Bot | 8531149f43 | |
tusooa | 2504929da2 | |
Pleroma Renovate Bot | e1ef381162 | |
Pleroma Renovate Bot | 2f632b95cc | |
tusooa | 7c7385b1de | |
tusooa | 670ff6e940 | |
tusooa | 1364e56437 | |
tusooa | ebad6a17d2 | |
tusooa | 2d9ee02c12 | |
tusooa | 5f8a34c51d | |
tusooa | cd5d0a8b64 | |
tusooa | ca7b5b7deb | |
Henry Jameson | 1492937a7e | |
Henry Jameson | e0fbeee88e | |
Pleroma Renovate Bot | 17e7df9da3 | |
Pleroma Renovate Bot | e1d5add046 | |
Henry Jameson | 9aaa8a86f5 | |
Henry Jameson | d8ed541d12 | |
Henry Jameson | 4c158e636b | |
Henry Jameson | 3e1aeb6d2c | |
HJ | 80eddb1099 | |
XYenon | 01758a28ea | |
Pleroma Renovate Bot | 829ab46fdc | |
HJ | bc830cd033 | |
HJ | a814520709 | |
HJ | 9a8f52a38d | |
HJ | 9c376b3511 | |
HJ | ad5bd09204 | |
Pleroma Renovate Bot | 034ed86312 | |
Pleroma Renovate Bot | 0bcfde4c2e | |
tusooa | 1f7ec86b80 | |
tusooa | b0d1d65063 | |
tusooa | 5c0deb1e6f | |
Pleroma Renovate Bot | 6deb6d45c6 | |
tusooa | 33c2195064 | |
Pleroma Renovate Bot | d6cd3e9385 | |
Pleroma Renovate Bot | 251787ed07 | |
Henry Jameson | 9e5c7313c6 | |
Henry Jameson | ac75d051b7 | |
Henry Jameson | 7bb28bb23c | |
Henry Jameson | 3ac67ab727 | |
Henry Jameson | 4c3af5c362 | |
Henry Jameson | df9fe6d261 | |
Henry Jameson | ece69f01b7 | |
Henry Jameson | 9153417202 | |
Henry Jameson | c7a16bdfe2 | |
Henry Jameson | 6992439c92 | |
Henry Jameson | 2bf224e214 | |
Henry Jameson | 6b40fc9895 | |
Henry Jameson | 9a97e0d196 | |
Henry Jameson | 0b5e536b4c | |
Henry Jameson | 819cd41cf0 | |
Henry Jameson | 332ad77e35 | |
Henry Jameson | ab5408d36e | |
Henry Jameson | 27f63d5e50 | |
Henry Jameson | bfd802ad04 | |
Henry Jameson | 4d23d31fec | |
Henry Jameson | 9632b77786 | |
Henry Jameson | 55ea6df40b | |
Henry Jameson | 6a7b182af1 | |
Henry Jameson | 947b73f870 | |
Henry Jameson | ac32997f8b | |
Henry Jameson | af0cd54223 | |
tusooa | e516eee479 | |
Pleroma Renovate Bot | 796a006a99 | |
Pleroma Renovate Bot | ebf3a2de30 | |
tusooa | d1876503bc | |
tusooa | 5b56b6b9fd | |
HJ | 3a507ba9b2 |
|
@ -0,0 +1 @@
|
||||||
|
/build/webpack.prod.conf.js export-subst
|
|
@ -4,11 +4,36 @@
|
||||||
image: node:16
|
image: node:16
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
|
- check-changelog
|
||||||
- lint
|
- lint
|
||||||
- build
|
- build
|
||||||
- test
|
- test
|
||||||
- deploy
|
- deploy
|
||||||
|
|
||||||
|
# https://git.pleroma.social/help/ci/yaml/workflow.md#switch-between-branch-pipelines-and-merge-request-pipelines
|
||||||
|
workflow:
|
||||||
|
rules:
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||||
|
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
|
||||||
|
when: never
|
||||||
|
- if: $CI_COMMIT_BRANCH
|
||||||
|
|
||||||
|
check-changelog:
|
||||||
|
stage: check-changelog
|
||||||
|
image: alpine
|
||||||
|
rules:
|
||||||
|
- if: $CI_MERGE_REQUEST_SOURCE_PROJECT_PATH == 'pleroma/pleroma-fe' && $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^renovate/
|
||||||
|
when: never
|
||||||
|
- if: $CI_MERGE_REQUEST_SOURCE_PROJECT_PATH == 'pleroma/pleroma-fe' && $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == 'weblate'
|
||||||
|
when: never
|
||||||
|
- if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop"
|
||||||
|
before_script: ''
|
||||||
|
after_script: ''
|
||||||
|
cache: {}
|
||||||
|
script:
|
||||||
|
- apk add git
|
||||||
|
- sh ./tools/check-changelog
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
stage: lint
|
stage: lint
|
||||||
script:
|
script:
|
||||||
|
@ -18,6 +43,8 @@ lint:
|
||||||
|
|
||||||
test:
|
test:
|
||||||
stage: test
|
stage: test
|
||||||
|
tags:
|
||||||
|
- amd64
|
||||||
variables:
|
variables:
|
||||||
APT_CACHE_DIR: apt-cache
|
APT_CACHE_DIR: apt-cache
|
||||||
script:
|
script:
|
||||||
|
@ -29,6 +56,8 @@ test:
|
||||||
|
|
||||||
build:
|
build:
|
||||||
stage: build
|
stage: build
|
||||||
|
tags:
|
||||||
|
- amd64
|
||||||
script:
|
script:
|
||||||
- yarn
|
- yarn
|
||||||
- npm run build
|
- npm run build
|
||||||
|
|
31
CHANGELOG.md
31
CHANGELOG.md
|
@ -3,6 +3,37 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
|
## 2.6.1
|
||||||
|
### Fixed
|
||||||
|
- fix admin dashboard not having any feedback on frontend installation
|
||||||
|
- Fix frontend admin tab crashing when no primary frontend is set
|
||||||
|
- Add aria attributes to react and extra buttons
|
||||||
|
|
||||||
|
## 2.6.0
|
||||||
|
### Added
|
||||||
|
- add the initial i18n translation file for Taiwanese (Hokkien), and modify some related files.
|
||||||
|
- Implemented a very basic instance administration screen
|
||||||
|
- Implement quoting
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Keep aspect ratio of custom emoji reaction in notification
|
||||||
|
- Fix openSettingsModalTab so that it correctly opens Settings modal instead of Admin modal
|
||||||
|
- Add alt text to emoji picker buttons
|
||||||
|
- Use export-subst gitattribute to allow tarball builds
|
||||||
|
- fix reports now showing reason/content
|
||||||
|
- Fix HTML attribute parsing, discard attributes not strating with a letter
|
||||||
|
- Make MentionsLine aware of line breaking by non-br elements
|
||||||
|
- Fix a bug where mentioning a user twice will not fill the mention into the textarea
|
||||||
|
- Fix parsing non-ascii tags
|
||||||
|
- Fix OAuth2 token lingering after revocation
|
||||||
|
- fix regex issue in HTML parser/renderer
|
||||||
|
- don't display quoted status twice
|
||||||
|
- fix typo in code that prevented cards from showing at all
|
||||||
|
- Fix react button not working if reaction accounts are not loaded
|
||||||
|
- Fix react button misalignment on safari ios
|
||||||
|
- Fix pinned statuses gone when reloading user timeline
|
||||||
|
- Fix scrolling emoji selector in modal in safari ios
|
||||||
|
|
||||||
## 2.5.1
|
## 2.5.1
|
||||||
### Fixed
|
### Fixed
|
||||||
- Checkboxes in settings can now work with screenreaders
|
- Checkboxes in settings can now work with screenreaders
|
||||||
|
|
|
@ -11,9 +11,16 @@ var env = process.env.NODE_ENV === 'testing'
|
||||||
? require('../config/test.env')
|
? require('../config/test.env')
|
||||||
: config.build.env
|
: config.build.env
|
||||||
|
|
||||||
let commitHash = require('child_process')
|
let commitHash = (() => {
|
||||||
|
const subst = "$Format:%h$";
|
||||||
|
if(!subst.match(/Format:/)) {
|
||||||
|
return subst;
|
||||||
|
} else {
|
||||||
|
return require('child_process')
|
||||||
.execSync('git rev-parse --short HEAD')
|
.execSync('git rev-parse --short HEAD')
|
||||||
.toString();
|
.toString();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
var webpackConfig = merge(baseWebpackConfig, {
|
var webpackConfig = merge(baseWebpackConfig, {
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Make Pleroma FE to also view apng (Animated PNG) attachment.
|
|
@ -0,0 +1 @@
|
||||||
|
Added emoji pack management to the admin panel
|
|
@ -0,0 +1 @@
|
||||||
|
stop using that one runner for intensive tasks
|
|
@ -0,0 +1 @@
|
||||||
|
Create a link to the URL of the scrobble when it's present
|
|
@ -0,0 +1 @@
|
||||||
|
Fix native notifications appearing as many times as there are open tabs. Clicking on notification will focus last focused tab.
|
|
@ -0,0 +1 @@
|
||||||
|
Support showing extra notifications in the notifications column
|
|
@ -0,0 +1 @@
|
||||||
|
Focusing into a tab clears all current desktop notifications
|
|
@ -0,0 +1 @@
|
||||||
|
Support group actors
|
|
@ -0,0 +1 @@
|
||||||
|
Allow hiding custom emojis in picker.
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed error that appeared on mobile Chrome(ium) (and derivatives) when native notifications are allowed
|
|
@ -0,0 +1 @@
|
||||||
|
Added option to not mark all notifications when closing notifications drawer on mobile, this creates a new button to mark all as seen.
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed being unable to set notification visibility for reports and follow requests
|
|
@ -0,0 +1 @@
|
||||||
|
Added ability to mute sensitive posts (ported from eintei)
|
|
@ -0,0 +1 @@
|
||||||
|
Added option to toggle what notification types appear in native notifications, by default less important ones (likes, repeats, etc) will no longer show up in native notifications.
|
|
@ -0,0 +1 @@
|
||||||
|
Native notifications now also have "badge" property that matches instance's favicon (visible in Android Chromium at least)
|
|
@ -0,0 +1 @@
|
||||||
|
The expiry date indication won't be shown if the poll never expires
|
|
@ -0,0 +1 @@
|
||||||
|
Added option to treat non-interactive notifications (likes, repeats et all) as seen for visual purposes (no read mark, ignored in counters, still can show in native notifications)
|
|
@ -0,0 +1 @@
|
||||||
|
Synchronized requested notification types with backend, hopefully should fix missing notifications for polls and follow requests
|
|
@ -0,0 +1 @@
|
||||||
|
Interacting (opening reply box etc) or simply clicking on non-interactive notifications now marks them as read. Clicking on native notifications for non-interactive ones also marks them as seen.
|
|
@ -0,0 +1 @@
|
||||||
|
Notifications are no longer sorted by "seen" status since interacting with them can change their read status and makes UI jumpy. Old behavior can be restored in settings.
|
|
@ -0,0 +1 @@
|
||||||
|
Add poll end notifications to fetched types.
|
|
@ -0,0 +1 @@
|
||||||
|
Display public favorites on user profiles
|
|
@ -0,0 +1 @@
|
||||||
|
Display quotes count on posts and add quotes list page
|
|
@ -0,0 +1 @@
|
||||||
|
Show a dedicated registration notice page when further action is required after registering
|
|
@ -0,0 +1 @@
|
||||||
|
Option to only show scrobbles that are recent enough
|
|
@ -0,0 +1 @@
|
||||||
|
Notifications are now shown through a serviceworker (since mobile chrome does not allow them otherwise), it's always enabled, even if previously we only enabled it for WebPush notifications only. If you don't like websites "running" while closed, check how to disable them in your browser. Old way to show notifications will be used as a fallback but might not have all the new features.
|
|
@ -0,0 +1 @@
|
||||||
|
Shows the most recent scrobble under each post when available
|
|
@ -0,0 +1 @@
|
||||||
|
Display loading and error indicator for conversation page
|
|
@ -0,0 +1 @@
|
||||||
|
Add caching system for themes3
|
|
@ -0,0 +1 @@
|
||||||
|
fix color inputs and some in-development themes3 issues
|
|
@ -0,0 +1 @@
|
||||||
|
Overhauled the way themes work, migrating to new Pleroma Interface Style Sheets system.
|
|
@ -0,0 +1 @@
|
||||||
|
unread notifications should now properly catch up (eventually) in polling mode
|
|
@ -0,0 +1 @@
|
||||||
|
Video posters on Safari
|
|
@ -0,0 +1 @@
|
||||||
|
nothing
|
|
@ -0,0 +1 @@
|
||||||
|
Added option to always "show" notifications when using web push for better compatibility with some browsers (chrome, edge, safari)
|
|
@ -3,8 +3,8 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
|
||||||
<!--server-generated-meta-->
|
|
||||||
<link rel="icon" type="image/png" href="/favicon.png">
|
<link rel="icon" type="image/png" href="/favicon.png">
|
||||||
|
<!--server-generated-meta-->
|
||||||
</head>
|
</head>
|
||||||
<body class="hidden">
|
<body class="hidden">
|
||||||
<noscript>To use Pleroma, please enable JavaScript.</noscript>
|
<noscript>To use Pleroma, please enable JavaScript.</noscript>
|
||||||
|
|
58
package.json
58
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "pleroma_fe",
|
"name": "pleroma_fe",
|
||||||
"version": "2.5.0",
|
"version": "2.6.1",
|
||||||
"description": "Pleroma frontend, the default frontend of Pleroma social network server",
|
"description": "Pleroma frontend, the default frontend of Pleroma social network server",
|
||||||
"author": "Pleroma contributors <https://git.pleroma.social/pleroma/pleroma-fe/-/blob/develop/CONTRIBUTORS.md>",
|
"author": "Pleroma contributors <https://git.pleroma.social/pleroma/pleroma-fe/-/blob/develop/CONTRIBUTORS.md>",
|
||||||
"private": false,
|
"private": false,
|
||||||
|
@ -16,29 +16,29 @@
|
||||||
"lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs"
|
"lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "7.21.0",
|
"@babel/runtime": "7.21.5",
|
||||||
"@chenfengyuan/vue-qrcode": "2.0.0",
|
"@chenfengyuan/vue-qrcode": "2.0.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "6.3.0",
|
"@fortawesome/fontawesome-svg-core": "6.4.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "6.3.0",
|
"@fortawesome/free-regular-svg-icons": "6.4.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "6.3.0",
|
"@fortawesome/free-solid-svg-icons": "6.4.0",
|
||||||
"@fortawesome/vue-fontawesome": "3.0.3",
|
"@fortawesome/vue-fontawesome": "3.0.3",
|
||||||
"@kazvmoe-infra/pinch-zoom-element": "1.2.0",
|
"@kazvmoe-infra/pinch-zoom-element": "1.2.0",
|
||||||
"@kazvmoe-infra/unicode-emoji-json": "0.4.0",
|
"@kazvmoe-infra/unicode-emoji-json": "0.4.0",
|
||||||
"@ruffle-rs/ruffle": "0.1.0-nightly.2022.7.12",
|
"@ruffle-rs/ruffle": "0.1.0-nightly.2024.3.17",
|
||||||
"@vuelidate/core": "2.0.0",
|
"@vuelidate/core": "2.0.3",
|
||||||
"@vuelidate/validators": "2.0.0",
|
"@vuelidate/validators": "2.0.4",
|
||||||
"body-scroll-lock": "3.1.5",
|
"body-scroll-lock": "3.1.5",
|
||||||
"chromatism": "3.0.0",
|
"chromatism": "3.0.0",
|
||||||
"click-outside-vue3": "4.0.1",
|
"click-outside-vue3": "4.0.1",
|
||||||
"cropperjs": "1.5.12",
|
"cropperjs": "1.5.13",
|
||||||
"escape-html": "1.0.3",
|
"escape-html": "1.0.3",
|
||||||
"js-cookie": "3.0.1",
|
"hash-sum": "^2.0.0",
|
||||||
|
"js-cookie": "3.0.5",
|
||||||
"localforage": "1.10.0",
|
"localforage": "1.10.0",
|
||||||
"parse-link-header": "2.0.0",
|
"parse-link-header": "2.0.0",
|
||||||
"phoenix": "1.6.2",
|
"phoenix": "1.7.7",
|
||||||
"pinia": "^2.0.33",
|
|
||||||
"punycode.js": "2.3.0",
|
"punycode.js": "2.3.0",
|
||||||
"qrcode": "1.5.0",
|
"qrcode": "1.5.3",
|
||||||
"querystring-es3": "0.2.1",
|
"querystring-es3": "0.2.1",
|
||||||
"url": "0.11.0",
|
"url": "0.11.0",
|
||||||
"utf8": "3.0.0",
|
"utf8": "3.0.0",
|
||||||
|
@ -50,19 +50,19 @@
|
||||||
"vuex": "4.1.0"
|
"vuex": "4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.21.0",
|
"@babel/core": "7.21.8",
|
||||||
"@babel/eslint-parser": "7.19.1",
|
"@babel/eslint-parser": "7.21.8",
|
||||||
"@babel/plugin-transform-runtime": "7.21.0",
|
"@babel/plugin-transform-runtime": "7.21.4",
|
||||||
"@babel/preset-env": "7.20.2",
|
"@babel/preset-env": "7.21.5",
|
||||||
"@babel/register": "7.21.0",
|
"@babel/register": "7.21.0",
|
||||||
"@intlify/vue-i18n-loader": "5.0.1",
|
"@intlify/vue-i18n-loader": "5.0.1",
|
||||||
"@ungap/event-target": "0.2.3",
|
"@ungap/event-target": "0.2.4",
|
||||||
"@vue/babel-helper-vue-jsx-merge-props": "1.4.0",
|
"@vue/babel-helper-vue-jsx-merge-props": "1.4.0",
|
||||||
"@vue/babel-plugin-jsx": "1.1.1",
|
"@vue/babel-plugin-jsx": "1.2.1",
|
||||||
"@vue/compiler-sfc": "3.2.45",
|
"@vue/compiler-sfc": "3.2.45",
|
||||||
"@vue/test-utils": "2.2.8",
|
"@vue/test-utils": "2.2.8",
|
||||||
"autoprefixer": "10.4.13",
|
"autoprefixer": "10.4.19",
|
||||||
"babel-loader": "9.1.2",
|
"babel-loader": "9.1.3",
|
||||||
"babel-plugin-lodash": "3.3.4",
|
"babel-plugin-lodash": "3.3.4",
|
||||||
"chai": "4.3.7",
|
"chai": "4.3.7",
|
||||||
"chalk": "1.1.3",
|
"chalk": "1.1.3",
|
||||||
|
@ -70,7 +70,7 @@
|
||||||
"connect-history-api-fallback": "2.0.0",
|
"connect-history-api-fallback": "2.0.0",
|
||||||
"copy-webpack-plugin": "11.0.0",
|
"copy-webpack-plugin": "11.0.0",
|
||||||
"cross-spawn": "7.0.3",
|
"cross-spawn": "7.0.3",
|
||||||
"css-loader": "6.7.3",
|
"css-loader": "6.10.0",
|
||||||
"css-minimizer-webpack-plugin": "4.2.2",
|
"css-minimizer-webpack-plugin": "4.2.2",
|
||||||
"custom-event-polyfill": "1.0.7",
|
"custom-event-polyfill": "1.0.7",
|
||||||
"eslint": "8.33.0",
|
"eslint": "8.33.0",
|
||||||
|
@ -84,11 +84,11 @@
|
||||||
"eventsource-polyfill": "0.9.6",
|
"eventsource-polyfill": "0.9.6",
|
||||||
"express": "4.18.2",
|
"express": "4.18.2",
|
||||||
"function-bind": "1.1.1",
|
"function-bind": "1.1.1",
|
||||||
"html-webpack-plugin": "5.5.0",
|
"html-webpack-plugin": "5.5.1",
|
||||||
"http-proxy-middleware": "2.0.6",
|
"http-proxy-middleware": "2.0.6",
|
||||||
"iso-639-1": "2.1.15",
|
"iso-639-1": "2.1.15",
|
||||||
"json-loader": "0.5.7",
|
"json-loader": "0.5.7",
|
||||||
"karma": "6.4.1",
|
"karma": "6.4.2",
|
||||||
"karma-coverage": "2.2.0",
|
"karma-coverage": "2.2.0",
|
||||||
"karma-firefox-launcher": "2.1.2",
|
"karma-firefox-launcher": "2.1.2",
|
||||||
"karma-mocha": "2.0.1",
|
"karma-mocha": "2.0.1",
|
||||||
|
@ -98,22 +98,22 @@
|
||||||
"karma-spec-reporter": "0.0.36",
|
"karma-spec-reporter": "0.0.36",
|
||||||
"karma-webpack": "5.0.0",
|
"karma-webpack": "5.0.0",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"mini-css-extract-plugin": "2.7.2",
|
"mini-css-extract-plugin": "2.7.6",
|
||||||
"mocha": "10.2.0",
|
"mocha": "10.2.0",
|
||||||
"nightwatch": "2.6.19",
|
"nightwatch": "2.6.25",
|
||||||
"opn": "5.5.0",
|
"opn": "5.5.0",
|
||||||
"ora": "0.4.1",
|
"ora": "0.4.1",
|
||||||
"postcss": "8.4.20",
|
"postcss": "8.4.23",
|
||||||
"postcss-html": "^1.5.0",
|
"postcss-html": "^1.5.0",
|
||||||
"postcss-loader": "7.0.2",
|
"postcss-loader": "7.0.2",
|
||||||
"postcss-scss": "^4.0.6",
|
"postcss-scss": "^4.0.6",
|
||||||
"sass": "1.60.0",
|
"sass": "1.60.0",
|
||||||
"sass-loader": "13.2.0",
|
"sass-loader": "13.2.2",
|
||||||
"selenium-server": "2.53.1",
|
"selenium-server": "2.53.1",
|
||||||
"semver": "7.3.8",
|
"semver": "7.3.8",
|
||||||
"serviceworker-webpack5-plugin": "2.0.0",
|
"serviceworker-webpack5-plugin": "2.0.0",
|
||||||
"shelljs": "0.8.5",
|
"shelljs": "0.8.5",
|
||||||
"sinon": "15.0.1",
|
"sinon": "15.0.4",
|
||||||
"sinon-chai": "3.7.0",
|
"sinon-chai": "3.7.0",
|
||||||
"stylelint": "14.16.1",
|
"stylelint": "14.16.1",
|
||||||
"stylelint-config-html": "^1.1.0",
|
"stylelint-config-html": "^1.1.0",
|
||||||
|
|
10
src/App.js
10
src/App.js
|
@ -17,8 +17,6 @@ import GlobalNoticeList from './components/global_notice_list/global_notice_list
|
||||||
import { windowWidth, windowHeight } from './services/window_utils/window_utils'
|
import { windowWidth, windowHeight } from './services/window_utils/window_utils'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import { defineAsyncComponent } from 'vue'
|
import { defineAsyncComponent } from 'vue'
|
||||||
import { useShoutStore } from './stores/shout'
|
|
||||||
import { useInterfaceStore } from './stores/interface'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
|
@ -88,7 +86,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
shout () { return useShoutStore().joined },
|
shout () { return this.$store.state.shout.joined },
|
||||||
suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
|
suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
|
||||||
showInstanceSpecificPanel () {
|
showInstanceSpecificPanel () {
|
||||||
return this.$store.state.instance.showInstanceSpecificPanel &&
|
return this.$store.state.instance.showInstanceSpecificPanel &&
|
||||||
|
@ -114,7 +112,7 @@ export default {
|
||||||
hideShoutbox () {
|
hideShoutbox () {
|
||||||
return this.$store.getters.mergedConfig.hideShoutbox
|
return this.$store.getters.mergedConfig.hideShoutbox
|
||||||
},
|
},
|
||||||
layoutType () { return useInterfaceStore().layoutType },
|
layoutType () { return this.$store.state.interface.layoutType },
|
||||||
privateMode () { return this.$store.state.instance.private },
|
privateMode () { return this.$store.state.instance.private },
|
||||||
reverseLayout () {
|
reverseLayout () {
|
||||||
const { thirdColumnMode, sidebarRight: reverseSetting } = this.$store.getters.mergedConfig
|
const { thirdColumnMode, sidebarRight: reverseSetting } = this.$store.getters.mergedConfig
|
||||||
|
@ -130,8 +128,8 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateMobileState () {
|
updateMobileState () {
|
||||||
useInterfaceStore().setLayoutWidth(windowWidth())
|
this.$store.dispatch('setLayoutWidth', windowWidth())
|
||||||
useInterfaceStore().setLayoutHeight(windowHeight())
|
this.$store.dispatch('setLayoutHeight', windowHeight())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
448
src/App.scss
448
src/App.scss
|
@ -1,9 +1,10 @@
|
||||||
// stylelint-disable rscss/class-format
|
// stylelint-disable rscss/class-format
|
||||||
/* stylelint-disable no-descending-specificity */
|
/* stylelint-disable no-descending-specificity */
|
||||||
@import "./variables";
|
|
||||||
@import "./panel";
|
@import "./panel";
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
--font-size: 14px;
|
||||||
|
--status-margin: 0.75em;
|
||||||
--navbar-height: 3.5rem;
|
--navbar-height: 3.5rem;
|
||||||
--post-line-height: 1.4;
|
--post-line-height: 1.4;
|
||||||
// Z-Index stuff
|
// Z-Index stuff
|
||||||
|
@ -13,19 +14,21 @@
|
||||||
--ZI_navbar_popovers: 7500;
|
--ZI_navbar_popovers: 7500;
|
||||||
--ZI_navbar: 7000;
|
--ZI_navbar: 7000;
|
||||||
--ZI_popovers: 6000;
|
--ZI_popovers: 6000;
|
||||||
|
|
||||||
|
// Fallback for when stuff is loading
|
||||||
|
--background: var(--bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-size: 14px;
|
font-size: var(--font-size);
|
||||||
// overflow-x: clip causes my browser's tab to crash with SIGILL lul
|
// overflow-x: clip causes my browser's tab to crash with SIGILL lul
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-family: var(--interfaceFont, sans-serif);
|
font-family: var(--font);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: $fallback--text;
|
color: var(--text);
|
||||||
color: var(--text, $fallback--text);
|
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
overscroll-behavior-y: none;
|
overscroll-behavior-y: none;
|
||||||
|
@ -42,17 +45,35 @@ body {
|
||||||
// have a cursor/pointer to operate them
|
// have a cursor/pointer to operate them
|
||||||
@media (any-pointer: fine) {
|
@media (any-pointer: fine) {
|
||||||
* {
|
* {
|
||||||
scrollbar-color: var(--btn) transparent;
|
scrollbar-color: var(--fg) transparent;
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-corner {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-resizer {
|
||||||
|
/* stylelint-disable-next-line declaration-no-important */
|
||||||
|
background-color: transparent !important;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(
|
||||||
|
135deg,
|
||||||
|
transparent calc(50% - 1px),
|
||||||
|
var(--textFaint) 50%,
|
||||||
|
transparent calc(50% + 1px),
|
||||||
|
transparent calc(75% - 1px),
|
||||||
|
var(--textFaint) 75%,
|
||||||
|
transparent calc(75% + 1px),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
&::-webkit-scrollbar-button,
|
&::-webkit-scrollbar-button,
|
||||||
&::-webkit-scrollbar-thumb {
|
&::-webkit-scrollbar-thumb {
|
||||||
background-color: var(--btn);
|
box-shadow: var(--shadow);
|
||||||
box-shadow: var(--buttonShadow);
|
border-radius: var(--roundness);
|
||||||
border-radius: var(--btnRadius);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// horizontal/vertical/increment/decrement are webkit-specific stuff
|
// horizontal/vertical/increment/decrement are webkit-specific stuff
|
||||||
|
@ -61,7 +82,7 @@ body {
|
||||||
&::-webkit-scrollbar-button {
|
&::-webkit-scrollbar-button {
|
||||||
--___bgPadding: 2px;
|
--___bgPadding: 2px;
|
||||||
|
|
||||||
color: var(--btnText);
|
color: var(--text);
|
||||||
background-repeat: no-repeat, no-repeat;
|
background-repeat: no-repeat, no-repeat;
|
||||||
|
|
||||||
&:horizontal {
|
&:horizontal {
|
||||||
|
@ -69,15 +90,15 @@ body {
|
||||||
|
|
||||||
&:increment {
|
&:increment {
|
||||||
background-image:
|
background-image:
|
||||||
linear-gradient(45deg, var(--btnText) 50%, transparent 51%),
|
linear-gradient(45deg, var(--text) 50%, transparent 51%),
|
||||||
linear-gradient(-45deg, transparent 50%, var(--btnText) 51%);
|
linear-gradient(-45deg, transparent 50%, var(--text) 51%);
|
||||||
background-position: top var(--___bgPadding) left 50%, right 50% bottom var(--___bgPadding);
|
background-position: top var(--___bgPadding) left 50%, right 50% bottom var(--___bgPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:decrement {
|
&:decrement {
|
||||||
background-image:
|
background-image:
|
||||||
linear-gradient(45deg, transparent 50%, var(--btnText) 51%),
|
linear-gradient(45deg, transparent 50%, var(--text) calc(50% + 1px)),
|
||||||
linear-gradient(-45deg, var(--btnText) 50%, transparent 51%);
|
linear-gradient(-45deg, var(--text) 50%, transparent 51%);
|
||||||
background-position: bottom var(--___bgPadding) right 50%, left 50% top var(--___bgPadding);
|
background-position: bottom var(--___bgPadding) right 50%, left 50% top var(--___bgPadding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,15 +108,15 @@ body {
|
||||||
|
|
||||||
&:increment {
|
&:increment {
|
||||||
background-image:
|
background-image:
|
||||||
linear-gradient(-45deg, transparent 50%, var(--btnText) 51%),
|
linear-gradient(-45deg, transparent 50%, var(--text) 51%),
|
||||||
linear-gradient(45deg, transparent 50%, var(--btnText) 51%);
|
linear-gradient(45deg, transparent 50%, var(--text) 51%);
|
||||||
background-position: right var(--___bgPadding) top 50%, left var(--___bgPadding) top 50%;
|
background-position: right var(--___bgPadding) top 50%, left var(--___bgPadding) top 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:decrement {
|
&:decrement {
|
||||||
background-image:
|
background-image:
|
||||||
linear-gradient(-45deg, var(--btnText) 50%, transparent 51%),
|
linear-gradient(-45deg, var(--text) 50%, transparent 51%),
|
||||||
linear-gradient(45deg, var(--btnText) 50%, transparent 51%);
|
linear-gradient(45deg, var(--text) 50%, transparent 51%);
|
||||||
background-position: left var(--___bgPadding) top 50%, right var(--___bgPadding) top 50%;
|
background-position: left var(--___bgPadding) top 50%, right var(--___bgPadding) top 50%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,15 +125,14 @@ body {
|
||||||
}
|
}
|
||||||
// Body should have background to scrollbar otherwise it will use white (body color?)
|
// Body should have background to scrollbar otherwise it will use white (body color?)
|
||||||
html {
|
html {
|
||||||
scrollbar-color: var(--selectedMenu) var(--wallpaper);
|
scrollbar-color: var(--fg) var(--wallpaper);
|
||||||
background: var(--wallpaper);
|
background: var(--wallpaper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: $fallback--link;
|
color: var(--link);
|
||||||
color: var(--link, $fallback--link);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
|
@ -128,27 +148,12 @@ h4 {
|
||||||
i[class*="icon-"],
|
i[class*="icon-"],
|
||||||
.svg-inline--fa,
|
.svg-inline--fa,
|
||||||
.iconLetter {
|
.iconLetter {
|
||||||
color: $fallback--icon;
|
color: var(--icon);
|
||||||
color: var(--icon, $fallback--icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-unstyled:hover,
|
|
||||||
a:hover {
|
|
||||||
> i[class*="icon-"],
|
|
||||||
> .svg-inline--fa,
|
|
||||||
> .iconLetter {
|
|
||||||
color: var(--text);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
z-index: var(--ZI_navbar);
|
z-index: var(--ZI_navbar);
|
||||||
background-color: $fallback--fg;
|
box-shadow: var(--shadow);
|
||||||
background-color: var(--topBar, $fallback--fg);
|
|
||||||
color: $fallback--faint;
|
|
||||||
color: var(--faint, $fallback--faint);
|
|
||||||
box-shadow: 0 0 4px rgb(0 0 0 / 60%);
|
|
||||||
box-shadow: var(--topBarShadow);
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: var(--navbar-height);
|
height: var(--navbar-height);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -195,8 +200,7 @@ nav {
|
||||||
grid-column: 1 / span 3;
|
grid-column: 1 / span 3;
|
||||||
grid-row: 1 / 1;
|
grid-row: 1 / 1;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
background-color: rgb(0 0 0 / 15%);
|
background-color: var(--underlay);
|
||||||
background-color: var(--underlay, rgb(0 0 0 / 15%));
|
|
||||||
z-index: -1000;
|
z-index: -1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +208,6 @@ nav {
|
||||||
--miniColumn: 25rem;
|
--miniColumn: 25rem;
|
||||||
--maxiColumn: 45rem;
|
--maxiColumn: 45rem;
|
||||||
--columnGap: 1em;
|
--columnGap: 1em;
|
||||||
--status-margin: 0.75em;
|
|
||||||
--effectiveSidebarColumnWidth: minmax(var(--miniColumn), var(--sidebarColumnWidth, var(--miniColumn)));
|
--effectiveSidebarColumnWidth: minmax(var(--miniColumn), var(--sidebarColumnWidth, var(--miniColumn)));
|
||||||
--effectiveNotifsColumnWidth: minmax(var(--miniColumn), var(--notifsColumnWidth, var(--miniColumn)));
|
--effectiveNotifsColumnWidth: minmax(var(--miniColumn), var(--notifsColumnWidth, var(--miniColumn)));
|
||||||
--effectiveContentColumnWidth: minmax(var(--miniColumn), var(--contentColumnWidth, var(--maxiColumn)));
|
--effectiveContentColumnWidth: minmax(var(--miniColumn), var(--contentColumnWidth, var(--maxiColumn)));
|
||||||
|
@ -366,106 +369,113 @@ nav {
|
||||||
|
|
||||||
.button-default {
|
.button-default {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
color: $fallback--text;
|
color: var(--text);
|
||||||
color: var(--btnText, $fallback--text);
|
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--btn, $fallback--fg);
|
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: $fallback--btnRadius;
|
border-radius: var(--roundness);
|
||||||
border-radius: var(--btnRadius, $fallback--btnRadius);
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: $fallback--buttonShadow;
|
background-color: var(--background);
|
||||||
box-shadow: var(--buttonShadow);
|
box-shadow: var(--shadow);
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-family: var(--interfaceFont, sans-serif);
|
font-family: var(--font);
|
||||||
|
|
||||||
&.-sublime {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
i[class*="icon-"],
|
|
||||||
.svg-inline--fa {
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--btnText, $fallback--text);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-moz-focus-inner {
|
&::-moz-focus-inner {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
|
||||||
box-shadow: 0 0 4px rgb(255 255 255 / 30%);
|
|
||||||
box-shadow: var(--buttonHoverShadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
box-shadow:
|
|
||||||
0 0 4px 0 rgb(255 255 255 / 30%),
|
|
||||||
0 1px 0 0 rgb(0 0 0 / 20%) inset,
|
|
||||||
0 -1px 0 0 rgb(255 255 255 / 20%) inset;
|
|
||||||
box-shadow: var(--buttonPressedShadow);
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--btnPressedText, $fallback--text);
|
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--btnPressed, $fallback--fg);
|
|
||||||
|
|
||||||
svg,
|
|
||||||
i {
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--btnPressedText, $fallback--text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--btnDisabledText, $fallback--text);
|
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--btnDisabled, $fallback--fg);
|
|
||||||
|
|
||||||
svg,
|
|
||||||
i {
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--btnDisabledText, $fallback--text);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item,
|
||||||
|
.list-item {
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
text-align: initial;
|
||||||
|
font-size: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
font-weight: 400;
|
||||||
|
cursor: pointer;
|
||||||
|
color: inherit;
|
||||||
|
clear: both;
|
||||||
|
position: relative;
|
||||||
|
white-space: nowrap;
|
||||||
|
border-color: var(--border);
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 0;
|
||||||
|
border-top-width: 1px;
|
||||||
|
width: 100%;
|
||||||
|
line-height: var(--__line-height);
|
||||||
|
padding: var(--__vertical-gap) var(--__horizontal-gap);
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
--__line-height: 1.5em;
|
||||||
|
--__horizontal-gap: 0.75em;
|
||||||
|
--__vertical-gap: 0.5em;
|
||||||
|
|
||||||
|
&.-non-interactive {
|
||||||
|
cursor: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.toggled {
|
&.-active,
|
||||||
color: $fallback--text;
|
&:hover {
|
||||||
color: var(--btnToggledText, $fallback--text);
|
border-top-width: 1px;
|
||||||
background-color: $fallback--fg;
|
border-bottom-width: 1px;
|
||||||
background-color: var(--btnToggled, $fallback--fg);
|
|
||||||
box-shadow:
|
|
||||||
0 0 4px 0 rgb(255 255 255 / 30%),
|
|
||||||
0 1px 0 0 rgb(0 0 0 / 20%) inset,
|
|
||||||
0 -1px 0 0 rgb(255 255 255 / 20%) inset;
|
|
||||||
box-shadow: var(--buttonPressedShadow);
|
|
||||||
|
|
||||||
svg,
|
|
||||||
i {
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--btnToggledText, $fallback--text);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.danger {
|
&.-active + &,
|
||||||
// TODO: add better color variable
|
&:hover + & {
|
||||||
color: $fallback--text;
|
border-top-width: 0;
|
||||||
color: var(--alertErrorPanelText, $fallback--text);
|
}
|
||||||
background-color: $fallback--alertError;
|
|
||||||
background-color: var(--alertError, $fallback--alertError);
|
&:hover + .menu-item-collapsible:not(.-expanded) + &,
|
||||||
|
&.-active + .menu-item-collapsible:not(.-expanded) + & {
|
||||||
|
border-top-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[aria-expanded="true"] {
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a,
|
||||||
|
button:not(.button-default) {
|
||||||
|
text-align: initial;
|
||||||
|
padding: 0;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
display: inline;
|
||||||
|
font-size: 100%;
|
||||||
|
font-family: inherit;
|
||||||
|
line-height: unset;
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
border-top-right-radius: var(--roundness);
|
||||||
|
border-top-left-radius: var(--roundness);
|
||||||
|
border-top-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom-right-radius: var(--roundness);
|
||||||
|
border-bottom-left-radius: var(--roundness);
|
||||||
|
border-bottom-width: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-unstyled {
|
.button-unstyled {
|
||||||
background: none;
|
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
display: inline;
|
display: inline;
|
||||||
text-align: initial;
|
text-align: initial;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
background-color: transparent;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
line-height: unset;
|
line-height: unset;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -473,28 +483,23 @@ nav {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
|
||||||
&.-link {
|
&.-link {
|
||||||
color: $fallback--link;
|
/* stylelint-disable-next-line declaration-no-important */
|
||||||
color: var(--link, $fallback--link);
|
color: var(--link) !important;
|
||||||
}
|
|
||||||
|
|
||||||
&.-fullwidth {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.-hover-highlight {
|
|
||||||
&:hover svg {
|
|
||||||
color: $fallback--lightText;
|
|
||||||
color: var(--lightText, $fallback--lightText);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input,
|
input,
|
||||||
textarea,
|
textarea {
|
||||||
|
border: none;
|
||||||
|
display: inline-block;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
&.unstyled {
|
&.unstyled {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
background: none;
|
/* stylelint-disable-next-line declaration-no-important */
|
||||||
|
background: none !important;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
height: unset;
|
height: unset;
|
||||||
}
|
}
|
||||||
|
@ -502,19 +507,11 @@ textarea,
|
||||||
--_padding: 0.5em;
|
--_padding: 0.5em;
|
||||||
|
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: $fallback--inputRadius;
|
border-radius: var(--roundness);
|
||||||
border-radius: var(--inputRadius, $fallback--inputRadius);
|
background-color: var(--background);
|
||||||
box-shadow:
|
color: var(--text);
|
||||||
0 1px 0 0 rgb(0 0 0 / 20%) inset,
|
box-shadow: var(--shadow);
|
||||||
0 -1px 0 0 rgb(255 255 255 / 20%) inset,
|
font-family: var(--font);
|
||||||
0 0 2px 0 rgb(0 0 0 / 100%) inset;
|
|
||||||
box-shadow: var(--inputShadow);
|
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--input, $fallback--fg);
|
|
||||||
color: $fallback--lightText;
|
|
||||||
color: var(--inputText, $fallback--lightText);
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-family: var(--inputFont, sans-serif);
|
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@ -528,7 +525,6 @@ textarea,
|
||||||
&[disabled="disabled"],
|
&[disabled="disabled"],
|
||||||
&.disabled {
|
&.disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
opacity: 0.5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&[type="range"] {
|
&[type="range"] {
|
||||||
|
@ -543,9 +539,9 @@ textarea,
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
&:checked + label::before {
|
&:checked + label::before {
|
||||||
box-shadow: 0 0 2px black inset, 0 0 0 4px $fallback--fg inset;
|
box-shadow: var(--shadow);
|
||||||
box-shadow: var(--inputShadow), 0 0 0 4px var(--fg, $fallback--fg) inset;
|
background-color: var(--background);
|
||||||
background-color: var(--accent, $fallback--link);
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
|
@ -559,16 +555,14 @@ textarea,
|
||||||
+ label::before {
|
+ label::before {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
content: "";
|
content: "•";
|
||||||
transition: box-shadow 200ms;
|
transition: box-shadow 200ms;
|
||||||
width: 1.1em;
|
width: 1.1em;
|
||||||
height: 1.1em;
|
height: 1.1em;
|
||||||
border-radius: 100%; // Radio buttons should always be circle
|
border-radius: 100%; // Radio buttons should always be circle
|
||||||
box-shadow: 0 0 2px black inset;
|
background-color: var(--background);
|
||||||
box-shadow: var(--inputShadow);
|
box-shadow: var(--shadow);
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--input, $fallback--fg);
|
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
|
@ -581,8 +575,9 @@ textarea,
|
||||||
|
|
||||||
&[type="checkbox"] {
|
&[type="checkbox"] {
|
||||||
&:checked + label::before {
|
&:checked + label::before {
|
||||||
color: $fallback--text;
|
color: var(--text);
|
||||||
color: var(--inputText, $fallback--text);
|
background-color: var(--background);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
|
@ -600,13 +595,9 @@ textarea,
|
||||||
transition: color 200ms;
|
transition: color 200ms;
|
||||||
width: 1.1em;
|
width: 1.1em;
|
||||||
height: 1.1em;
|
height: 1.1em;
|
||||||
border-radius: $fallback--checkboxRadius;
|
border-radius: var(--roundness);
|
||||||
border-radius: var(--checkboxRadius, $fallback--checkboxRadius);
|
box-shadow: var(--shadow);
|
||||||
box-shadow: 0 0 2px black inset;
|
|
||||||
box-shadow: var(--inputShadow);
|
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--input, $fallback--fg);
|
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
|
@ -623,16 +614,14 @@ textarea,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Textareas should have stock line-height + vertical padding instead of huge line-height
|
// Textareas should have stock line-height + vertical padding instead of huge line-height
|
||||||
textarea {
|
textarea.input {
|
||||||
padding: var(--_padding);
|
padding: var(--_padding);
|
||||||
line-height: var(--post-line-height);
|
line-height: var(--post-line-height);
|
||||||
}
|
}
|
||||||
|
|
||||||
option {
|
option {
|
||||||
color: $fallback--text;
|
color: var(--text);
|
||||||
color: var(--text, $fallback--text);
|
background-color: var(--background);
|
||||||
background-color: $fallback--bg;
|
|
||||||
background-color: var(--bg, $fallback--bg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hide-number-spinner {
|
.hide-number-spinner {
|
||||||
|
@ -645,6 +634,20 @@ option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cards-list {
|
||||||
|
list-style: none;
|
||||||
|
display: grid;
|
||||||
|
grid-auto-flow: row dense;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
|
||||||
|
li {
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--roundness);
|
||||||
|
padding: 0.5em;
|
||||||
|
margin: 0.25em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.btn-block {
|
.btn-block {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -655,16 +658,19 @@ option {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
||||||
button {
|
button,
|
||||||
|
.button-dropdown {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
|
||||||
&:not(:last-child) {
|
&:not(:last-child),
|
||||||
|
&:not(:last-child) .button-default {
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:first-child) {
|
&:not(:first-child),
|
||||||
|
&:not(:first-child) .button-default {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
}
|
}
|
||||||
|
@ -697,74 +703,58 @@ option {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
&.badge-notification {
|
&.-dot,
|
||||||
background-color: $fallback--cRed;
|
&.-counter {
|
||||||
background-color: var(--badgeNotification, $fallback--cRed);
|
margin: 0;
|
||||||
color: white;
|
position: absolute;
|
||||||
color: var(--badgeNotificationText, white);
|
}
|
||||||
|
|
||||||
|
&.-dot {
|
||||||
|
min-height: 8px;
|
||||||
|
max-height: 8px;
|
||||||
|
min-width: 8px;
|
||||||
|
max-width: 8px;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 0;
|
||||||
|
font-size: 0;
|
||||||
|
left: calc(50% - 4px);
|
||||||
|
top: calc(50% - 4px);
|
||||||
|
margin-left: 6px;
|
||||||
|
margin-top: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.-counter {
|
||||||
|
border-radius: var(--roundness);
|
||||||
|
font-size: 0.75em;
|
||||||
|
line-height: 1;
|
||||||
|
text-align: right;
|
||||||
|
padding: 0.2em;
|
||||||
|
min-width: 0;
|
||||||
|
left: calc(50% - 0.5em);
|
||||||
|
top: calc(50% - 0.4em);
|
||||||
|
margin-left: 0.7em;
|
||||||
|
margin-top: -1em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert {
|
.alert {
|
||||||
margin: 0 0.35em;
|
margin: 0 0.35em;
|
||||||
padding: 0 0.25em;
|
padding: 0 0.25em;
|
||||||
border-radius: $fallback--tooltipRadius;
|
border-radius: var(--roundness);
|
||||||
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
|
border: 1px solid var(--border);
|
||||||
|
|
||||||
&.error {
|
|
||||||
background-color: $fallback--alertError;
|
|
||||||
background-color: var(--alertError, $fallback--alertError);
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--alertErrorText, $fallback--text);
|
|
||||||
|
|
||||||
.panel-heading & {
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--alertErrorPanelText, $fallback--text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.warning {
|
|
||||||
background-color: $fallback--alertWarning;
|
|
||||||
background-color: var(--alertWarning, $fallback--alertWarning);
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--alertWarningText, $fallback--text);
|
|
||||||
|
|
||||||
.panel-heading & {
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--alertWarningPanelText, $fallback--text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.success {
|
|
||||||
background-color: var(--alertSuccess, $fallback--alertWarning);
|
|
||||||
color: var(--alertSuccessText, $fallback--text);
|
|
||||||
|
|
||||||
.panel-heading & {
|
|
||||||
color: var(--alertSuccessPanelText, $fallback--text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.faint {
|
.faint {
|
||||||
color: $fallback--faint;
|
--text: var(--textFaint);
|
||||||
color: var(--faint, $fallback--faint);
|
--link: var(--linkFaint);
|
||||||
}
|
|
||||||
|
|
||||||
.faint-link {
|
color: var(--text);
|
||||||
color: $fallback--faint;
|
|
||||||
color: var(--faint, $fallback--faint);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.visibility-notice {
|
.visibility-notice {
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
border: 1px solid $fallback--faint;
|
border: 1px solid var(--textFaint);
|
||||||
border: 1px solid var(--faint, $fallback--faint);
|
border-radius: var(--roundness);
|
||||||
border-radius: $fallback--inputRadius;
|
|
||||||
border-radius: var(--inputRadius, $fallback--inputRadius);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.notice-dismissible {
|
.notice-dismissible {
|
||||||
|
@ -785,6 +775,10 @@ option {
|
||||||
&.iconLetter {
|
&.iconLetter {
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.svg-inline--fa {
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fa-old-padding {
|
.fa-old-padding {
|
||||||
|
@ -799,6 +793,11 @@ option {
|
||||||
opacity: 0.25;
|
opacity: 0.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timeago {
|
||||||
|
--link: var(--text);
|
||||||
|
--linkFaint: var(--textFaint);
|
||||||
|
}
|
||||||
|
|
||||||
.login-hint {
|
.login-hint {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
@ -897,3 +896,8 @@ option {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*::selection {
|
||||||
|
color: var(--selectionText);
|
||||||
|
background-color: var(--selectionBackground);
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
|
v-show="$store.state.interface.themeApplied"
|
||||||
id="app-loaded"
|
id="app-loaded"
|
||||||
:style="bgStyle"
|
:style="bgStyle"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
$main-color: #f58d2c;
|
|
||||||
$main-background: white;
|
|
||||||
$darkened-background: whitesmoke;
|
|
||||||
|
|
||||||
$fallback--bg: #121a24;
|
|
||||||
$fallback--fg: #182230;
|
|
||||||
$fallback--faint: rgb(185 185 186 / 50%);
|
|
||||||
$fallback--text: #b9b9ba;
|
|
||||||
$fallback--link: #d8a070;
|
|
||||||
$fallback--icon: #666;
|
|
||||||
$fallback--lightBg: rgb(21 30 42);
|
|
||||||
$fallback--lightText: #b9b9ba;
|
|
||||||
$fallback--border: #222;
|
|
||||||
$fallback--cRed: #f00;
|
|
||||||
$fallback--cBlue: #0095ff;
|
|
||||||
$fallback--cGreen: #0fa00f;
|
|
||||||
$fallback--cOrange: orange;
|
|
||||||
|
|
||||||
$fallback--alertError: rgb(211 16 20 / 50%);
|
|
||||||
$fallback--alertWarning: rgb(111 111 20 / 50%);
|
|
||||||
|
|
||||||
$fallback--panelRadius: 10px;
|
|
||||||
$fallback--checkboxRadius: 2px;
|
|
||||||
$fallback--btnRadius: 4px;
|
|
||||||
$fallback--inputRadius: 4px;
|
|
||||||
$fallback--tooltipRadius: 5px;
|
|
||||||
$fallback--avatarRadius: 4px;
|
|
||||||
$fallback--avatarAltRadius: 10px;
|
|
||||||
$fallback--attachmentRadius: 10px;
|
|
||||||
$fallback--chatMessageRadius: 10px;
|
|
||||||
|
|
||||||
$fallback--buttonShadow: 0 0 2px 0 rgb(0 0 0 / 100%),
|
|
||||||
0 1px 0 0 rgb(255 255 255 / 20%) inset,
|
|
||||||
0 -1px 0 0 rgb(0 0 0 / 20%) inset;
|
|
||||||
|
|
||||||
$status-margin: 0.75em;
|
|
|
@ -14,12 +14,9 @@ import { windowWidth, windowHeight } from '../services/window_utils/window_utils
|
||||||
import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
|
import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
|
||||||
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
|
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
|
||||||
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
|
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
|
||||||
import { applyTheme, applyConfig } from '../services/style_setter/style_setter.js'
|
import { applyTheme, applyConfig, tryLoadCache } from '../services/style_setter/style_setter.js'
|
||||||
import FaviconService from '../services/favicon_service/favicon_service.js'
|
import FaviconService from '../services/favicon_service/favicon_service.js'
|
||||||
|
import { initServiceWorker, updateFocus } from '../services/sw/sw.js'
|
||||||
import { useI18nStore } from '../stores/i18n'
|
|
||||||
import { useInterfaceStore } from '../stores/interface'
|
|
||||||
import { useAnnouncementsStore } from '../stores/announcements'
|
|
||||||
|
|
||||||
let staticInitialResults = null
|
let staticInitialResults = null
|
||||||
|
|
||||||
|
@ -263,6 +260,8 @@ const getNodeInfo = async ({ store }) => {
|
||||||
store.dispatch('setInstanceOption', { name: 'editingAvailable', value: features.includes('editing') })
|
store.dispatch('setInstanceOption', { name: 'editingAvailable', value: features.includes('editing') })
|
||||||
store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits })
|
store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits })
|
||||||
store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled })
|
store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled })
|
||||||
|
store.dispatch('setInstanceOption', { name: 'quotingAvailable', value: features.includes('quote_posting') })
|
||||||
|
store.dispatch('setInstanceOption', { name: 'groupActorAvailable', value: features.includes('pleroma:group_actors') })
|
||||||
|
|
||||||
const uploadLimits = metadata.uploadLimits
|
const uploadLimits = metadata.uploadLimits
|
||||||
store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) })
|
store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) })
|
||||||
|
@ -329,8 +328,6 @@ const setConfig = async ({ store }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkOAuthToken = async ({ store }) => {
|
const checkOAuthToken = async ({ store }) => {
|
||||||
// eslint-disable-next-line no-async-promise-executor
|
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
if (store.getters.getUserToken()) {
|
if (store.getters.getUserToken()) {
|
||||||
try {
|
try {
|
||||||
await store.dispatch('loginUser', store.getters.getUserToken())
|
await store.dispatch('loginUser', store.getters.getUserToken())
|
||||||
|
@ -338,22 +335,17 @@ const checkOAuthToken = async ({ store }) => {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolve()
|
return Promise.resolve()
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
|
const afterStoreSetup = async ({ store, i18n }) => {
|
||||||
const app = createApp(App)
|
store.dispatch('setLayoutWidth', windowWidth())
|
||||||
app.use(pinia)
|
store.dispatch('setLayoutHeight', windowHeight())
|
||||||
|
|
||||||
if (storageError) {
|
|
||||||
useInterfaceStore().pushGlobalNotice({ messageKey: 'errors.storage_unavailable', level: 'error' })
|
|
||||||
}
|
|
||||||
|
|
||||||
useInterfaceStore().setLayoutWidth(windowWidth())
|
|
||||||
useInterfaceStore().setLayoutHeight(windowHeight())
|
|
||||||
|
|
||||||
FaviconService.initFaviconService()
|
FaviconService.initFaviconService()
|
||||||
|
initServiceWorker(store)
|
||||||
|
|
||||||
|
window.addEventListener('focus', () => updateFocus())
|
||||||
|
|
||||||
const overrides = window.___pleromafe_dev_overrides || {}
|
const overrides = window.___pleromafe_dev_overrides || {}
|
||||||
const server = (typeof overrides.target !== 'undefined') ? overrides.target : window.location.origin
|
const server = (typeof overrides.target !== 'undefined') ? overrides.target : window.location.origin
|
||||||
|
@ -361,21 +353,26 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
|
||||||
|
|
||||||
await setConfig({ store })
|
await setConfig({ store })
|
||||||
|
|
||||||
const { customTheme, customThemeSource } = store.state.config
|
const { customTheme, customThemeSource, forceThemeRecompilation } = store.state.config
|
||||||
const { theme } = store.state.instance
|
const { theme } = store.state.instance
|
||||||
const customThemePresent = customThemeSource || customTheme
|
const customThemePresent = customThemeSource || customTheme
|
||||||
|
|
||||||
|
if (!forceThemeRecompilation && tryLoadCache()) {
|
||||||
|
store.commit('setThemeApplied')
|
||||||
|
} else {
|
||||||
if (customThemePresent) {
|
if (customThemePresent) {
|
||||||
if (customThemeSource && customThemeSource.themeEngineVersion === CURRENT_VERSION) {
|
if (customThemeSource && customThemeSource.themeEngineVersion === CURRENT_VERSION) {
|
||||||
applyTheme(customThemeSource)
|
applyTheme(customThemeSource)
|
||||||
} else {
|
} else {
|
||||||
applyTheme(customTheme)
|
applyTheme(customTheme)
|
||||||
}
|
}
|
||||||
|
store.commit('setThemeApplied')
|
||||||
} else if (theme) {
|
} else if (theme) {
|
||||||
// do nothing, it will load asynchronously
|
// do nothing, it will load asynchronously
|
||||||
} else {
|
} else {
|
||||||
console.error('Failed to load any theme!')
|
console.error('Failed to load any theme!')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
applyConfig(store.state.config)
|
applyConfig(store.state.config)
|
||||||
|
|
||||||
|
@ -390,7 +387,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
|
||||||
|
|
||||||
// Start fetching things that don't need to block the UI
|
// Start fetching things that don't need to block the UI
|
||||||
store.dispatch('fetchMutes')
|
store.dispatch('fetchMutes')
|
||||||
useAnnouncementsStore().startFetchingAnnouncements()
|
store.dispatch('startFetchingAnnouncements')
|
||||||
getTOS({ store })
|
getTOS({ store })
|
||||||
getStickers({ store })
|
getStickers({ store })
|
||||||
|
|
||||||
|
@ -405,7 +402,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
useI18nStore().setI18n(i18n)
|
const app = createApp(App)
|
||||||
|
|
||||||
app.use(router)
|
app.use(router)
|
||||||
app.use(store)
|
app.use(store)
|
||||||
|
|
|
@ -25,6 +25,7 @@ import ListsTimeline from 'components/lists_timeline/lists_timeline.vue'
|
||||||
import ListsEdit from 'components/lists_edit/lists_edit.vue'
|
import ListsEdit from 'components/lists_edit/lists_edit.vue'
|
||||||
import NavPanel from 'src/components/nav_panel/nav_panel.vue'
|
import NavPanel from 'src/components/nav_panel/nav_panel.vue'
|
||||||
import AnnouncementsPage from 'components/announcements_page/announcements_page.vue'
|
import AnnouncementsPage from 'components/announcements_page/announcements_page.vue'
|
||||||
|
import QuotesTimeline from '../components/quotes_timeline/quotes_timeline.vue'
|
||||||
|
|
||||||
export default (store) => {
|
export default (store) => {
|
||||||
const validateAuthenticatedRoute = (to, from, next) => {
|
const validateAuthenticatedRoute = (to, from, next) => {
|
||||||
|
@ -51,6 +52,7 @@ export default (store) => {
|
||||||
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
|
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
|
||||||
{ name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline },
|
{ name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline },
|
||||||
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
|
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
|
||||||
|
{ name: 'quotes', path: '/notice/:id/quotes', component: QuotesTimeline },
|
||||||
{
|
{
|
||||||
name: 'remote-user-profile-acct',
|
name: 'remote-user-profile-acct',
|
||||||
path: '/remote-users/:_(@)?:username([^/@]+)@:hostname([^/@]+)',
|
path: '/remote-users/:_(@)?:username([^/@]+)@:hostname([^/@]+)',
|
||||||
|
|
|
@ -7,7 +7,6 @@ import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
faEllipsisV
|
faEllipsisV
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import { useReportsStore } from '../../stores/reports'
|
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
faEllipsisV
|
faEllipsisV
|
||||||
|
@ -74,7 +73,7 @@ const AccountActions = {
|
||||||
this.hideConfirmRemoveUserFromFollowers()
|
this.hideConfirmRemoveUserFromFollowers()
|
||||||
},
|
},
|
||||||
reportUser () {
|
reportUser () {
|
||||||
useReportsStore().openUserReportingModal({ userId: this.user.id })
|
this.$store.dispatch('openUserReportingModal', { userId: this.user.id })
|
||||||
},
|
},
|
||||||
openChat () {
|
openChat () {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
|
|
|
@ -11,14 +11,14 @@
|
||||||
<template v-if="relationship.following">
|
<template v-if="relationship.following">
|
||||||
<button
|
<button
|
||||||
v-if="relationship.showing_reblogs"
|
v-if="relationship.showing_reblogs"
|
||||||
class="btn button-default dropdown-item"
|
class="dropdown-item menu-item"
|
||||||
@click="hideRepeats"
|
@click="hideRepeats"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.hide_repeats') }}
|
{{ $t('user_card.hide_repeats') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="!relationship.showing_reblogs"
|
v-if="!relationship.showing_reblogs"
|
||||||
class="btn button-default dropdown-item"
|
class="dropdown-item menu-item"
|
||||||
@click="showRepeats"
|
@click="showRepeats"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.show_repeats') }}
|
{{ $t('user_card.show_repeats') }}
|
||||||
|
@ -31,34 +31,34 @@
|
||||||
<UserListMenu :user="user" />
|
<UserListMenu :user="user" />
|
||||||
<button
|
<button
|
||||||
v-if="relationship.followed_by"
|
v-if="relationship.followed_by"
|
||||||
class="btn button-default btn-block dropdown-item"
|
class="dropdown-item menu-item"
|
||||||
@click="removeUserFromFollowers"
|
@click="removeUserFromFollowers"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.remove_follower') }}
|
{{ $t('user_card.remove_follower') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="relationship.blocking"
|
v-if="relationship.blocking"
|
||||||
class="btn button-default btn-block dropdown-item"
|
class="dropdown-item menu-item"
|
||||||
@click="unblockUser"
|
@click="unblockUser"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.unblock') }}
|
{{ $t('user_card.unblock') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
class="btn button-default btn-block dropdown-item"
|
class="dropdown-item menu-item"
|
||||||
@click="blockUser"
|
@click="blockUser"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.block') }}
|
{{ $t('user_card.block') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn button-default btn-block dropdown-item"
|
class="dropdown-item menu-item"
|
||||||
@click="reportUser"
|
@click="reportUser"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.report') }}
|
{{ $t('user_card.report') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="pleromaChatMessagesAvailable"
|
v-if="pleromaChatMessagesAvailable"
|
||||||
class="btn button-default btn-block dropdown-item"
|
class="dropdown-item menu-item"
|
||||||
@click="openChat"
|
@click="openChat"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.message') }}
|
{{ $t('user_card.message') }}
|
||||||
|
@ -122,19 +122,12 @@
|
||||||
<script src="./account_actions.js"></script>
|
<script src="./account_actions.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
.AccountActions {
|
.AccountActions {
|
||||||
.ellipsis-button {
|
.ellipsis-button {
|
||||||
width: 2.5em;
|
width: 2.5em;
|
||||||
margin: -0.5em 0;
|
margin: -0.5em 0;
|
||||||
padding: 0.5em 0;
|
padding: 0.5em 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
&:not(:hover) .icon {
|
|
||||||
color: $fallback--lightText;
|
|
||||||
color: var(--lightText, $fallback--lightText);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
export default {
|
||||||
|
name: 'Alert',
|
||||||
|
selector: '.alert',
|
||||||
|
validInnerComponents: [
|
||||||
|
'Text',
|
||||||
|
'Icon',
|
||||||
|
'Link',
|
||||||
|
'Border',
|
||||||
|
'ButtonUnstyled'
|
||||||
|
],
|
||||||
|
variants: {
|
||||||
|
normal: '.neutral',
|
||||||
|
error: '.error',
|
||||||
|
warning: '.warning',
|
||||||
|
success: '.success'
|
||||||
|
},
|
||||||
|
defaultRules: [
|
||||||
|
{
|
||||||
|
directives: {
|
||||||
|
background: '--text',
|
||||||
|
opacity: 0.5,
|
||||||
|
blur: '9px'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parent: {
|
||||||
|
component: 'Alert'
|
||||||
|
},
|
||||||
|
component: 'Border',
|
||||||
|
textColor: '--parent'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
variant: 'error',
|
||||||
|
directives: {
|
||||||
|
background: '--cRed'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
variant: 'warning',
|
||||||
|
directives: {
|
||||||
|
background: '--cOrange'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
variant: 'success',
|
||||||
|
directives: {
|
||||||
|
background: '--cGreen'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ import { mapState } from 'vuex'
|
||||||
import AnnouncementEditor from '../announcement_editor/announcement_editor.vue'
|
import AnnouncementEditor from '../announcement_editor/announcement_editor.vue'
|
||||||
import RichContent from '../rich_content/rich_content.jsx'
|
import RichContent from '../rich_content/rich_content.jsx'
|
||||||
import localeService from '../../services/locale/locale.service.js'
|
import localeService from '../../services/locale/locale.service.js'
|
||||||
import { useAnnouncementsStore } from '../../stores/announcements'
|
|
||||||
|
|
||||||
const Announcement = {
|
const Announcement = {
|
||||||
components: {
|
components: {
|
||||||
|
@ -68,11 +67,11 @@ const Announcement = {
|
||||||
methods: {
|
methods: {
|
||||||
markAsRead () {
|
markAsRead () {
|
||||||
if (!this.isRead) {
|
if (!this.isRead) {
|
||||||
return useAnnouncementsStore().markAnnouncementAsRead(this.announcement.id)
|
return this.$store.dispatch('markAnnouncementAsRead', this.announcement.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteAnnouncement () {
|
deleteAnnouncement () {
|
||||||
return useAnnouncementsStore().deleteAnnouncement(this.announcement.id)
|
return this.$store.dispatch('deleteAnnouncement', this.announcement.id)
|
||||||
},
|
},
|
||||||
formatTimeOrDate (time, locale) {
|
formatTimeOrDate (time, locale) {
|
||||||
const d = new Date(time)
|
const d = new Date(time)
|
||||||
|
@ -86,7 +85,7 @@ const Announcement = {
|
||||||
this.editing = true
|
this.editing = true
|
||||||
},
|
},
|
||||||
submitEdit () {
|
submitEdit () {
|
||||||
useAnnouncementsStore().editAnnouncement({
|
this.$store.dispatch('editAnnouncement', {
|
||||||
id: this.announcement.id,
|
id: this.announcement.id,
|
||||||
...this.editedAnnouncement
|
...this.editedAnnouncement
|
||||||
})
|
})
|
||||||
|
|
|
@ -99,16 +99,14 @@
|
||||||
<script src="./announcement.js"></script>
|
<script src="./announcement.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
.announcement {
|
.announcement {
|
||||||
border-bottom: 1px solid var(--border, $fallback--border);
|
border-bottom: 1px solid var(--border);
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
padding: var(--status-margin, $status-margin);
|
padding: var(--status-margin);
|
||||||
|
|
||||||
.heading,
|
.heading,
|
||||||
.body {
|
.body {
|
||||||
margin-bottom: var(--status-margin, $status-margin);
|
margin-bottom: var(--status-margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<textarea
|
<textarea
|
||||||
ref="textarea"
|
ref="textarea"
|
||||||
v-model="announcement.content"
|
v-model="announcement.content"
|
||||||
class="post-textarea"
|
class="input post-textarea"
|
||||||
rows="1"
|
rows="1"
|
||||||
cols="1"
|
cols="1"
|
||||||
:placeholder="$t('announcements.post_placeholder')"
|
:placeholder="$t('announcements.post_placeholder')"
|
||||||
|
@ -14,6 +14,7 @@
|
||||||
<input
|
<input
|
||||||
id="announcement-start-time"
|
id="announcement-start-time"
|
||||||
v-model="announcement.startsAt"
|
v-model="announcement.startsAt"
|
||||||
|
class="input"
|
||||||
:type="announcement.allDay ? 'date' : 'datetime-local'"
|
:type="announcement.allDay ? 'date' : 'datetime-local'"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
>
|
>
|
||||||
|
@ -23,6 +24,7 @@
|
||||||
<input
|
<input
|
||||||
id="announcement-end-time"
|
id="announcement-end-time"
|
||||||
v-model="announcement.endsAt"
|
v-model="announcement.endsAt"
|
||||||
|
class="input"
|
||||||
:type="announcement.allDay ? 'date' : 'datetime-local'"
|
:type="announcement.allDay ? 'date' : 'datetime-local'"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
import Announcement from '../announcement/announcement.vue'
|
import Announcement from '../announcement/announcement.vue'
|
||||||
import AnnouncementEditor from '../announcement_editor/announcement_editor.vue'
|
import AnnouncementEditor from '../announcement_editor/announcement_editor.vue'
|
||||||
import { useAnnouncementsStore } from '../../stores/announcements'
|
|
||||||
|
|
||||||
const AnnouncementsPage = {
|
const AnnouncementsPage = {
|
||||||
components: {
|
components: {
|
||||||
|
@ -21,14 +20,14 @@ const AnnouncementsPage = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
useAnnouncementsStore().fetchAnnouncements()
|
this.$store.dispatch('fetchAnnouncements')
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
currentUser: state => state.users.currentUser
|
currentUser: state => state.users.currentUser
|
||||||
}),
|
}),
|
||||||
announcements () {
|
announcements () {
|
||||||
return useAnnouncementsStore().announcements
|
return this.$store.state.announcements.announcements
|
||||||
},
|
},
|
||||||
canPostAnnouncement () {
|
canPostAnnouncement () {
|
||||||
return this.currentUser && this.currentUser.privileges.includes('announcements_manage_announcements')
|
return this.currentUser && this.currentUser.privileges.includes('announcements_manage_announcements')
|
||||||
|
@ -37,7 +36,7 @@ const AnnouncementsPage = {
|
||||||
methods: {
|
methods: {
|
||||||
postAnnouncement () {
|
postAnnouncement () {
|
||||||
this.posting = true
|
this.posting = true
|
||||||
useAnnouncementsStore().postAnnouncement(this.newAnnouncement)
|
this.$store.dispatch('postAnnouncement', this.newAnnouncement)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.newAnnouncement.content = ''
|
this.newAnnouncement.content = ''
|
||||||
this.startsAt = undefined
|
this.startsAt = undefined
|
||||||
|
|
|
@ -61,15 +61,13 @@
|
||||||
<script src="./announcements_page.js"></script>
|
<script src="./announcements_page.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
.announcements-page {
|
.announcements-page {
|
||||||
.post-form {
|
.post-form {
|
||||||
padding: var(--status-margin, $status-margin);
|
padding: var(--status-margin);
|
||||||
|
|
||||||
.heading,
|
.heading,
|
||||||
.body {
|
.body {
|
||||||
margin-bottom: var(--status-margin, $status-margin);
|
margin-bottom: var(--status-margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-button {
|
.post-button {
|
||||||
|
|
|
@ -18,7 +18,6 @@ import {
|
||||||
faPencilAlt,
|
faPencilAlt,
|
||||||
faAlignRight
|
faAlignRight
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import { useMediaViewerStore } from '../../stores/media_viewer'
|
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
faFile,
|
faFile,
|
||||||
|
@ -148,14 +147,14 @@ const Attachment = {
|
||||||
openModal (event) {
|
openModal (event) {
|
||||||
if (this.useModal) {
|
if (this.useModal) {
|
||||||
this.$emit('setMedia')
|
this.$emit('setMedia')
|
||||||
useMediaViewerStore().setCurrentMedia(this.attachment)
|
this.$store.dispatch('setCurrentMedia', this.attachment)
|
||||||
} else if (this.type === 'unknown') {
|
} else if (this.type === 'unknown') {
|
||||||
window.open(this.attachment.url)
|
window.open(this.attachment.url)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openModalForce (event) {
|
openModalForce (event) {
|
||||||
this.$emit('setMedia')
|
this.$emit('setMedia')
|
||||||
useMediaViewerStore().setCurrentMedia(this.attachment)
|
this.$store.dispatch('setCurrentMedia', this.attachment)
|
||||||
},
|
},
|
||||||
onEdit (event) {
|
onEdit (event) {
|
||||||
this.edit && this.edit(this.attachment, event)
|
this.edit && this.edit(this.attachment, event)
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
.Attachment {
|
.Attachment {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -9,10 +7,8 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-radius: $fallback--attachmentRadius;
|
border-radius: var(--roundness);
|
||||||
border-radius: var(--attachmentRadius, $fallback--attachmentRadius);
|
border-color: var(--border);
|
||||||
border-color: $fallback--border;
|
|
||||||
border-color: var(--border, $fallback--border);
|
|
||||||
|
|
||||||
.attachment-wrapper {
|
.attachment-wrapper {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
@ -84,6 +80,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-container {
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
color: inherit;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.audio-container {
|
.audio-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
|
@ -126,23 +129,12 @@
|
||||||
|
|
||||||
.attachment-button {
|
.attachment-button {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border-radius: $fallback--tooltipRadius;
|
border-radius: var(--roundness);
|
||||||
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 2em;
|
width: 2em;
|
||||||
height: 2em;
|
height: 2em;
|
||||||
margin-left: 0.5em;
|
margin-left: 0.5em;
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
// TODO: theming? hard to theme with unknown background image color
|
|
||||||
background: rgb(230 230 230 / 70%);
|
|
||||||
|
|
||||||
.svg-inline--fa {
|
|
||||||
color: rgb(0 0 0 / 60%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover .svg-inline--fa {
|
|
||||||
color: rgb(0 0 0 / 90%);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,8 +209,7 @@
|
||||||
|
|
||||||
&.-placeholder {
|
&.-placeholder {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: $fallback--link;
|
color: var(--link);
|
||||||
color: var(--postLink, $fallback--link);
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
export default {
|
||||||
|
name: 'Attachment',
|
||||||
|
selector: '.Attachment',
|
||||||
|
validInnerComponents: [
|
||||||
|
'Border',
|
||||||
|
'ButtonUnstyled',
|
||||||
|
'Input'
|
||||||
|
],
|
||||||
|
defaultRules: [
|
||||||
|
{
|
||||||
|
directives: {
|
||||||
|
roundness: 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'ButtonUnstyled',
|
||||||
|
parent: { component: 'Attachment' },
|
||||||
|
directives: {
|
||||||
|
background: '#FFFFFF',
|
||||||
|
opacity: 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -38,7 +38,7 @@
|
||||||
v-if="edit"
|
v-if="edit"
|
||||||
v-model="localDescription"
|
v-model="localDescription"
|
||||||
type="text"
|
type="text"
|
||||||
class="description-field"
|
class="input description-field"
|
||||||
:placeholder="$t('post_status.media_description')"
|
:placeholder="$t('post_status.media_description')"
|
||||||
@keydown.enter.prevent=""
|
@keydown.enter.prevent=""
|
||||||
>
|
>
|
||||||
|
@ -175,7 +175,6 @@
|
||||||
:is="videoTag"
|
:is="videoTag"
|
||||||
v-if="type === 'video' && !hidden"
|
v-if="type === 'video' && !hidden"
|
||||||
class="video-container"
|
class="video-container"
|
||||||
:class="{ 'button-unstyled': 'isModal' }"
|
|
||||||
:href="attachment.url"
|
:href="attachment.url"
|
||||||
@click.stop.prevent="openModal"
|
@click.stop.prevent="openModal"
|
||||||
>
|
>
|
||||||
|
@ -253,7 +252,7 @@
|
||||||
v-if="edit"
|
v-if="edit"
|
||||||
v-model="localDescription"
|
v-model="localDescription"
|
||||||
type="text"
|
type="text"
|
||||||
class="description-field"
|
class="input description-field"
|
||||||
:placeholder="$t('post_status.media_description')"
|
:placeholder="$t('post_status.media_description')"
|
||||||
@keydown.enter.prevent=""
|
@keydown.enter.prevent=""
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
<!-- FIXME THIS NEEDS TO BE REFACTORED TO USE POPOVER -->
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-click-outside="onClickOutside"
|
v-click-outside="onClickOutside"
|
||||||
|
@ -6,12 +7,12 @@
|
||||||
<input
|
<input
|
||||||
v-model="term"
|
v-model="term"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
class="autosuggest-input"
|
class="input autosuggest-input"
|
||||||
@click="onInputClick"
|
@click="onInputClick"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="resultsVisible && filtered.length > 0"
|
v-if="resultsVisible && filtered.length > 0"
|
||||||
class="autosuggest-results"
|
class="panel autosuggest-results"
|
||||||
>
|
>
|
||||||
<slot
|
<slot
|
||||||
v-for="item in filtered"
|
v-for="item in filtered"
|
||||||
|
@ -24,8 +25,6 @@
|
||||||
<script src="./autosuggest.js"></script>
|
<script src="./autosuggest.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
.autosuggest {
|
.autosuggest {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
@ -40,18 +39,15 @@
|
||||||
top: 100%;
|
top: 100%;
|
||||||
right: 0;
|
right: 0;
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
background-color: $fallback--bg;
|
background-color: var(--bg);
|
||||||
background-color: var(--bg, $fallback--bg);
|
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-color: $fallback--border;
|
border-color: var(--border);
|
||||||
border-color: var(--border, $fallback--border);
|
border-radius: var(--roundness);
|
||||||
border-radius: $fallback--inputRadius;
|
|
||||||
border-radius: var(--inputRadius, $fallback--inputRadius);
|
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
box-shadow: 1px 1px 4px rgb(0 0 0 / 60%);
|
box-shadow: 1px 1px 4px rgb(0 0 0 / 60%);
|
||||||
box-shadow: var(--panelShadow);
|
box-shadow: var(--shadow);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
<script src="./avatar_list.js"></script>
|
<script src="./avatar_list.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
.avatars {
|
.avatars {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -36,8 +34,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-small {
|
.avatar-small {
|
||||||
border-radius: $fallback--avatarAltRadius;
|
border-radius: var(--roundness);
|
||||||
border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
|
|
||||||
height: 24px;
|
height: 24px;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
export default {
|
||||||
|
name: 'Badge',
|
||||||
|
selector: '.badge',
|
||||||
|
validInnerComponents: [
|
||||||
|
'Text',
|
||||||
|
'Icon'
|
||||||
|
],
|
||||||
|
variants: {
|
||||||
|
notification: '.-notification'
|
||||||
|
},
|
||||||
|
defaultRules: [
|
||||||
|
{
|
||||||
|
component: 'Root',
|
||||||
|
directives: {
|
||||||
|
'--badgeNotification': 'color | --cRed'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
directives: {
|
||||||
|
background: '--cGreen'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
variant: 'notification',
|
||||||
|
directives: {
|
||||||
|
background: '--cRed'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -47,7 +47,6 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1 0;
|
flex: 1 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0.6em 1em;
|
|
||||||
|
|
||||||
--emoji-size: 14px;
|
--emoji-size: 14px;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
export default {
|
||||||
|
name: 'Border',
|
||||||
|
selector: '/*border*/',
|
||||||
|
virtual: true,
|
||||||
|
defaultRules: [
|
||||||
|
{
|
||||||
|
directives: {
|
||||||
|
textColor: '$mod(--parent, 10)',
|
||||||
|
textAuto: 'no-auto'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
export default {
|
||||||
|
name: 'Button', // Name of the component
|
||||||
|
selector: '.button-default', // CSS selector/prefix
|
||||||
|
// outOfTreeSelector: '' // out-of-tree selector is used when other components are laid over it but it's not part of the tree, see Underlay component
|
||||||
|
// States, system witll calculate ALL possible combinations of those and prepend "normal" to them + standalone "normal" state
|
||||||
|
states: {
|
||||||
|
// States are a bit expensive - the amount of combinations generated is about (1/6)n^3+n, so adding more state increased number of combination by an order of magnitude!
|
||||||
|
// All states inherit from "normal" state, there is no other inheirtance, i.e. hover+disabled only inherits from "normal", not from hover nor disabled.
|
||||||
|
// However, cascading still works, so resulting state will be result of merging of all relevant states/variants
|
||||||
|
// normal: '' // normal state is implicitly added, it is always included
|
||||||
|
toggled: '.toggled',
|
||||||
|
pressed: ':active',
|
||||||
|
hover: ':hover:not(:disabled)',
|
||||||
|
focused: ':focus-within',
|
||||||
|
disabled: ':disabled'
|
||||||
|
},
|
||||||
|
// Variants are mutually exclusive, each component implicitly has "normal" variant, and all other variants inherit from it.
|
||||||
|
variants: {
|
||||||
|
// Variants save on computation time since adding new variant just adds one more "set".
|
||||||
|
// normal: '', // you can override normal variant, it will be appenended to the main class
|
||||||
|
danger: '.danger'
|
||||||
|
// Overall the compuation difficulty is N*((1/6)M^3+M) where M is number of distinct states and N is number of variants.
|
||||||
|
// This (currently) is further multipled by number of places where component can exist.
|
||||||
|
},
|
||||||
|
// This lists all other components that can possibly exist within one. Recursion is currently not supported (and probably won't be supported ever).
|
||||||
|
validInnerComponents: [
|
||||||
|
'Text',
|
||||||
|
'Icon'
|
||||||
|
],
|
||||||
|
// Default rules, used as "default theme", essentially.
|
||||||
|
defaultRules: [
|
||||||
|
{
|
||||||
|
component: 'Root',
|
||||||
|
directives: {
|
||||||
|
'--defaultButtonHoverGlow': 'shadow | 0 0 4 --text',
|
||||||
|
'--defaultButtonShadow': 'shadow | 0 0 2 #000000',
|
||||||
|
'--defaultButtonBevel': 'shadow | $borderSide(#FFFFFF, top, 0.2) | $borderSide(#000000, bottom, 0.2)',
|
||||||
|
'--pressedButtonBevel': 'shadow | $borderSide(#FFFFFF, bottom, 0.2)| $borderSide(#000000, top, 0.2)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// component: 'Button', // no need to specify components every time unless you're specifying how other component should look
|
||||||
|
// like within it
|
||||||
|
directives: {
|
||||||
|
background: '--fg',
|
||||||
|
shadow: ['--defaultButtonShadow', '--defaultButtonBevel'],
|
||||||
|
roundness: 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: ['hover'],
|
||||||
|
directives: {
|
||||||
|
shadow: ['--defaultButtonHoverGlow', '--defaultButtonBevel']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: ['pressed'],
|
||||||
|
directives: {
|
||||||
|
shadow: ['--defaultButtonShadow', '--pressedButtonBevel']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: ['hover', 'pressed'],
|
||||||
|
directives: {
|
||||||
|
shadow: ['--defaultButtonHoverGlow', '--pressedButtonBevel']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: ['toggled'],
|
||||||
|
directives: {
|
||||||
|
background: '--inheritedBackground,-14.2',
|
||||||
|
shadow: ['--defaultButtonShadow', '--pressedButtonBevel']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: ['toggled', 'hover'],
|
||||||
|
directives: {
|
||||||
|
background: '--inheritedBackground,-14.2',
|
||||||
|
shadow: ['--defaultButtonHoverGlow', '--pressedButtonBevel']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: ['disabled'],
|
||||||
|
directives: {
|
||||||
|
background: '$blend(--inheritedBackground, 0.25, --parent)',
|
||||||
|
shadow: ['--defaultButtonBevel']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Text',
|
||||||
|
parent: {
|
||||||
|
component: 'Button',
|
||||||
|
state: ['disabled']
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
textOpacity: 0.25,
|
||||||
|
textOpacityMode: 'blend'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
export default {
|
||||||
|
name: 'ButtonUnstyled',
|
||||||
|
selector: '.button-unstyled',
|
||||||
|
states: {
|
||||||
|
toggled: '.toggled',
|
||||||
|
disabled: ':disabled',
|
||||||
|
hover: ':hover:not(:disabled)',
|
||||||
|
focused: ':focus-within'
|
||||||
|
},
|
||||||
|
validInnerComponents: [
|
||||||
|
'Text',
|
||||||
|
'Icon',
|
||||||
|
'Badge'
|
||||||
|
],
|
||||||
|
defaultRules: [
|
||||||
|
{
|
||||||
|
directives: {
|
||||||
|
background: '#ffffff',
|
||||||
|
opacity: 0,
|
||||||
|
shadow: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Icon',
|
||||||
|
parent: {
|
||||||
|
component: 'ButtonUnstyled',
|
||||||
|
state: ['hover']
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
textColor: '--parent--text'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Icon',
|
||||||
|
parent: {
|
||||||
|
component: 'ButtonUnstyled',
|
||||||
|
state: ['toggled']
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
textColor: '--parent--text'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Icon',
|
||||||
|
parent: {
|
||||||
|
component: 'ButtonUnstyled',
|
||||||
|
state: ['toggled', 'hover']
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
textColor: '--parent--text'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Icon',
|
||||||
|
parent: {
|
||||||
|
component: 'ButtonUnstyled',
|
||||||
|
state: ['toggled', 'focused']
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
textColor: '--parent--text'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Icon',
|
||||||
|
parent: {
|
||||||
|
component: 'ButtonUnstyled',
|
||||||
|
state: ['toggled', 'focused', 'hover']
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
textColor: '--parent--text'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Text',
|
||||||
|
parent: {
|
||||||
|
component: 'ButtonUnstyled',
|
||||||
|
state: ['disabled']
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
textOpacity: 0.25,
|
||||||
|
textOpacityMode: 'blend'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Icon',
|
||||||
|
parent: {
|
||||||
|
component: 'ButtonUnstyled',
|
||||||
|
state: ['disabled']
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
textOpacity: 0.25,
|
||||||
|
textOpacityMode: 'blend'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { WSConnectionStatus } from '../../services/api/api.service.js'
|
import { WSConnectionStatus } from '../../services/api/api.service.js'
|
||||||
import { mapGetters, mapState } from 'vuex'
|
import { mapGetters, mapState } from 'vuex'
|
||||||
import { mapState as mapPiniaState } from 'pinia'
|
|
||||||
import ChatMessage from '../chat_message/chat_message.vue'
|
import ChatMessage from '../chat_message/chat_message.vue'
|
||||||
import PostStatusForm from '../post_status_form/post_status_form.vue'
|
import PostStatusForm from '../post_status_form/post_status_form.vue'
|
||||||
import ChatTitle from '../chat_title/chat_title.vue'
|
import ChatTitle from '../chat_title/chat_title.vue'
|
||||||
|
@ -14,7 +13,6 @@ import {
|
||||||
faChevronLeft
|
faChevronLeft
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import { buildFakeMessage } from '../../services/chat_utils/chat_utils.js'
|
import { buildFakeMessage } from '../../services/chat_utils/chat_utils.js'
|
||||||
import { useInterfaceStore } from '../../stores/interface.js'
|
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
faChevronDown,
|
faChevronDown,
|
||||||
|
@ -92,12 +90,10 @@ const Chat = {
|
||||||
'findOpenedChatByRecipientId',
|
'findOpenedChatByRecipientId',
|
||||||
'mergedConfig'
|
'mergedConfig'
|
||||||
]),
|
]),
|
||||||
...mapPiniaState(useInterfaceStore, {
|
|
||||||
mobileLayout: store => store.layoutType === 'mobile'
|
|
||||||
}),
|
|
||||||
...mapState({
|
...mapState({
|
||||||
backendInteractor: state => state.api.backendInteractor,
|
backendInteractor: state => state.api.backendInteractor,
|
||||||
mastoUserSocketStatus: state => state.api.mastoUserSocketStatus,
|
mastoUserSocketStatus: state => state.api.mastoUserSocketStatus,
|
||||||
|
mobileLayout: state => state.interface.layoutType === 'mobile',
|
||||||
currentUser: state => state.users.currentUser
|
currentUser: state => state.users.currentUser
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,15 +11,15 @@
|
||||||
|
|
||||||
.chat-view-body {
|
.chat-view-body {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background-color: var(--chatBg, $fallback--bg);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
min-height: calc(100vh - var(--navbar-height));
|
min-height: calc(100vh - var(--navbar-height));
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border-radius: 10px 10px 0 0;
|
border-radius: var(--roundness);
|
||||||
border-radius: var(--panelRadius, 10px) var(--panelRadius, 10px) 0 0;
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
@ -37,8 +37,6 @@
|
||||||
.footer {
|
.footer {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-color: $fallback--bg;
|
|
||||||
background-color: var(--bg, $fallback--bg);
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,8 +59,6 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 1.3em;
|
right: 1.3em;
|
||||||
top: -3.2em;
|
top: -3.2em;
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--btn, $fallback--fg);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -79,12 +75,6 @@
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
i {
|
|
||||||
font-size: 1em;
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--text, $fallback--text);
|
|
||||||
}
|
|
||||||
|
|
||||||
.unread-message-count {
|
.unread-message-count {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
export default {
|
||||||
|
name: 'Chat',
|
||||||
|
selector: '.chat-message-list',
|
||||||
|
validInnerComponents: [
|
||||||
|
'Text',
|
||||||
|
'Link',
|
||||||
|
'Icon',
|
||||||
|
'Avatar',
|
||||||
|
'ChatMessage'
|
||||||
|
],
|
||||||
|
defaultRules: [
|
||||||
|
{
|
||||||
|
directives: {
|
||||||
|
background: '--bg',
|
||||||
|
blur: '5px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -26,7 +26,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="message-list"
|
class="chat-message-list message-list"
|
||||||
:style="{ height: scrollableContainerHeight }"
|
:style="{ height: scrollableContainerHeight }"
|
||||||
>
|
>
|
||||||
<template v-if="!errorLoadingChat">
|
<template v-if="!errorLoadingChat">
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
<FAIcon icon="chevron-down" />
|
<FAIcon icon="chevron-down" />
|
||||||
<div
|
<div
|
||||||
v-if="newMessageCount"
|
v-if="newMessageCount"
|
||||||
class="badge badge-notification unread-chat-count unread-message-count"
|
class="badge -notification unread-chat-count unread-message-count"
|
||||||
>
|
>
|
||||||
{{ newMessageCount }}
|
{{ newMessageCount }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -95,6 +95,5 @@
|
||||||
|
|
||||||
<script src="./chat.js"></script>
|
<script src="./chat.js"></script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
@import "./chat";
|
@import "./chat";
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -45,8 +45,6 @@
|
||||||
<script src="./chat_list.js"></script>
|
<script src="./chat_list.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
.chat-list {
|
.chat-list {
|
||||||
min-height: 25em;
|
min-height: 25em;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
@ -57,8 +55,7 @@
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: $fallback--text;
|
color: var(--textFaint);
|
||||||
color: var(--faint, $fallback--text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
.chat-list-item {
|
.chat-list-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding: 0.75em;
|
|
||||||
height: 5em;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -11,11 +9,6 @@
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--selectedPost, $fallback--lightBg);
|
|
||||||
box-shadow: 0 0 3px 1px rgb(0 0 0 / 10%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-list-item-left {
|
.chat-list-item-left {
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +22,7 @@
|
||||||
|
|
||||||
.heading {
|
.heading {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: inline-flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
}
|
}
|
||||||
|
@ -47,18 +40,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-preview {
|
.chat-preview {
|
||||||
display: inline-flex;
|
display: flex;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
margin: 0.35em 0;
|
margin: 0.35em 0;
|
||||||
color: $fallback--text;
|
color: var(--textFaint);
|
||||||
color: var(--faint, $fallback--text);
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--faintLink, $fallback--link);
|
color: var(--linkFaint);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
@ -73,11 +65,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.Avatar {
|
|
||||||
border-radius: $fallback--avatarAltRadius;
|
|
||||||
border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-preview-body {
|
.chat-preview-body {
|
||||||
--emoji-size: 1.4em;
|
--emoji-size: 1.4em;
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="chat.unread > 0"
|
v-if="chat.unread > 0"
|
||||||
class="badge badge-notification unread-chat-count"
|
class="badge -notification unread-chat-count"
|
||||||
>
|
>
|
||||||
{{ chat.unread }}
|
{{ chat.unread }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -48,6 +48,5 @@
|
||||||
<script src="./chat_list_item.js"></script>
|
<script src="./chat_list_item.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
@import "./chat_list_item";
|
@import "./chat_list_item";
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { mapState, mapGetters } from 'vuex'
|
import { mapState, mapGetters } from 'vuex'
|
||||||
import { mapState as mapPiniaState } from 'pinia'
|
|
||||||
import Popover from '../popover/popover.vue'
|
import Popover from '../popover/popover.vue'
|
||||||
import Attachment from '../attachment/attachment.vue'
|
import Attachment from '../attachment/attachment.vue'
|
||||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||||
|
@ -13,7 +12,6 @@ import {
|
||||||
faTimes,
|
faTimes,
|
||||||
faEllipsisH
|
faEllipsisH
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import { useInterfaceStore } from '../../stores/interface'
|
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
faTimes,
|
faTimes,
|
||||||
|
@ -67,10 +65,8 @@ const ChatMessage = {
|
||||||
hasAttachment () {
|
hasAttachment () {
|
||||||
return this.message.attachments.length > 0
|
return this.message.attachments.length > 0
|
||||||
},
|
},
|
||||||
...mapPiniaState(useInterfaceStore, {
|
|
||||||
betterShadow: store => store.browserSupport.cssFilter
|
|
||||||
}),
|
|
||||||
...mapState({
|
...mapState({
|
||||||
|
betterShadow: state => state.interface.browserSupport.cssFilter,
|
||||||
currentUser: state => state.users.currentUser,
|
currentUser: state => state.users.currentUser,
|
||||||
restrictedNicknames: state => state.instance.restrictedNicknames
|
restrictedNicknames: state => state.instance.restrictedNicknames
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
.chat-message-wrapper {
|
.chat-message-wrapper {
|
||||||
&.hovered-message-chain {
|
&.hovered-message-chain {
|
||||||
.animated.Avatar {
|
.animated.Avatar {
|
||||||
|
@ -27,12 +25,6 @@
|
||||||
|
|
||||||
.menu-icon {
|
.menu-icon {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover,
|
|
||||||
.extra-button-popover.open & {
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--text, $fallback--text);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover {
|
.popover {
|
||||||
|
@ -61,10 +53,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.status {
|
.status {
|
||||||
border-radius: $fallback--chatMessageRadius;
|
background-color: var(--background);
|
||||||
border-radius: var(--chatMessageRadius, $fallback--chatMessageRadius);
|
color: var(--text);
|
||||||
|
border-radius: var(--roundness);
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0.75em;
|
padding: 0.75em;
|
||||||
|
border: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.created-at {
|
.created-at {
|
||||||
|
@ -97,8 +91,7 @@
|
||||||
.error {
|
.error {
|
||||||
.status-content.media-body,
|
.status-content.media-body,
|
||||||
.created-at {
|
.created-at {
|
||||||
color: $fallback--cRed;
|
color: var(--badgeNotification);
|
||||||
color: var(--badgeNotification, $fallback--cRed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,16 +110,6 @@
|
||||||
align-content: end;
|
align-content: end;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--chatMessageOutgoingLink, $fallback--link);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
color: var(--chatMessageOutgoingText, $fallback--text);
|
|
||||||
background-color: var(--chatMessageOutgoingBg, $fallback--lightBg);
|
|
||||||
border: 1px solid var(--chatMessageOutgoingBorder, --lightBg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-message-inner {
|
.chat-message-inner {
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
}
|
}
|
||||||
|
@ -137,22 +120,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.incoming {
|
.incoming {
|
||||||
a {
|
|
||||||
color: var(--chatMessageIncomingLink, $fallback--link);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
color: var(--chatMessageIncomingText, $fallback--text);
|
|
||||||
background-color: var(--chatMessageIncomingBg, $fallback--bg);
|
|
||||||
border: 1px solid var(--chatMessageIncomingBorder, --border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.created-at {
|
|
||||||
a {
|
|
||||||
color: var(--chatMessageIncomingText, $fallback--text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-message-menu {
|
.chat-message-menu {
|
||||||
left: 0.4rem;
|
left: 0.4rem;
|
||||||
}
|
}
|
||||||
|
@ -176,6 +143,5 @@
|
||||||
margin: 1.4em 0;
|
margin: 1.4em 0;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
color: $fallback--text;
|
color: var(--textFaint);
|
||||||
color: var(--faintedText, $fallback--text);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
export default {
|
||||||
|
name: 'ChatMessage',
|
||||||
|
selector: '.chat-message',
|
||||||
|
variants: {
|
||||||
|
outgoing: '.outgoing'
|
||||||
|
},
|
||||||
|
validInnerComponents: [
|
||||||
|
'Text',
|
||||||
|
'Icon',
|
||||||
|
'Border',
|
||||||
|
'Button',
|
||||||
|
'RichContent',
|
||||||
|
'Attachment',
|
||||||
|
'PollGraph'
|
||||||
|
],
|
||||||
|
defaultRules: [
|
||||||
|
{
|
||||||
|
directives: {
|
||||||
|
background: '--bg, 2',
|
||||||
|
backgroundNoCssColor: 'yes'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
variant: 'outgoing',
|
||||||
|
directives: {
|
||||||
|
background: '--bg, 5'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -53,7 +53,7 @@
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<button
|
<button
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
@click="deleteMessage"
|
@click="deleteMessage"
|
||||||
>
|
>
|
||||||
<FAIcon icon="times" /> {{ $t("chats.delete") }}
|
<FAIcon icon="times" /> {{ $t("chats.delete") }}
|
||||||
|
|
|
@ -16,11 +16,6 @@
|
||||||
padding-bottom: 0.7rem;
|
padding-bottom: 0.7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.basic-user-card:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: var(--selectedPost, $fallback--lightBg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.go-back-button {
|
.go-back-button {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
<div class="input-wrap">
|
<div class="input-wrap">
|
||||||
<div class="input-search">
|
<div class="input-search">
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
<input
|
<input
|
||||||
ref="search"
|
ref="search"
|
||||||
v-model="query"
|
v-model="query"
|
||||||
|
class="input"
|
||||||
placeholder="Search people"
|
placeholder="Search people"
|
||||||
@input="onInput"
|
@input="onInput"
|
||||||
>
|
>
|
||||||
|
@ -34,9 +36,9 @@
|
||||||
<div
|
<div
|
||||||
v-for="user in availableUsers"
|
v-for="user in availableUsers"
|
||||||
:key="user.id"
|
:key="user.id"
|
||||||
class="member"
|
class="list-item"
|
||||||
|
@click.capture.prevent="goToChat(user)"
|
||||||
>
|
>
|
||||||
<div @click.capture.prevent="goToChat(user)">
|
|
||||||
<BasicUserCard :user="user" />
|
<BasicUserCard :user="user" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -46,6 +48,5 @@
|
||||||
|
|
||||||
<script src="./chat_new.js"></script>
|
<script src="./chat_new.js"></script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
@import "./chat_new";
|
@import "./chat_new";
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -26,8 +26,6 @@
|
||||||
<script src="./chat_title.js"></script>
|
<script src="./chat_title.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
.chat-title {
|
.chat-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -54,8 +52,7 @@
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
height: 1.5em;
|
height: 1.5em;
|
||||||
width: 1.5em;
|
width: 1.5em;
|
||||||
border-radius: $fallback--avatarAltRadius;
|
border-radius: var(--roundness);
|
||||||
border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
|
|
||||||
|
|
||||||
&.animated::before {
|
&.animated::before {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<label
|
<label
|
||||||
class="checkbox"
|
class="checkbox"
|
||||||
:class="{ disabled, indeterminate }"
|
:class="{ disabled, indeterminate, 'indeterminate-fix': indeterminateTransitionFix }"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
@ -12,8 +12,9 @@
|
||||||
@change="$emit('update:modelValue', $event.target.checked)"
|
@change="$emit('update:modelValue', $event.target.checked)"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="checkbox-indicator"
|
class="input -checkbox checkbox-indicator"
|
||||||
:aria-hidden="true"
|
:aria-hidden="true"
|
||||||
|
@transitionend.capture="onTransitionEnd"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
v-if="!!$slots.default"
|
v-if="!!$slots.default"
|
||||||
|
@ -31,12 +32,28 @@ export default {
|
||||||
'indeterminate',
|
'indeterminate',
|
||||||
'disabled'
|
'disabled'
|
||||||
],
|
],
|
||||||
emits: ['update:modelValue']
|
emits: ['update:modelValue'],
|
||||||
|
data: (vm) => ({
|
||||||
|
indeterminateTransitionFix: vm.indeterminate
|
||||||
|
}),
|
||||||
|
watch: {
|
||||||
|
indeterminate (e) {
|
||||||
|
if (e) {
|
||||||
|
this.indeterminateTransitionFix = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onTransitionEnd (e) {
|
||||||
|
if (!this.indeterminate) {
|
||||||
|
this.indeterminateTransitionFix = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
@import "../../mixins";
|
@import "../../mixins";
|
||||||
|
|
||||||
.checkbox {
|
.checkbox {
|
||||||
|
@ -44,9 +61,15 @@ export default {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-height: 1.2em;
|
min-height: 1.2em;
|
||||||
|
|
||||||
&-indicator {
|
& > &-indicator {
|
||||||
|
/* Reset .input stuff */
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
line-height: inherit;
|
||||||
|
display: inline;
|
||||||
padding-left: 1.2em;
|
padding-left: 1.2em;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-indicator::before {
|
&-indicator::before {
|
||||||
|
@ -58,12 +81,9 @@ export default {
|
||||||
transition: color 200ms;
|
transition: color 200ms;
|
||||||
width: 1.1em;
|
width: 1.1em;
|
||||||
height: 1.1em;
|
height: 1.1em;
|
||||||
border-radius: $fallback--checkboxRadius;
|
border-radius: var(--roundness);
|
||||||
border-radius: var(--checkboxRadius, $fallback--checkboxRadius);
|
box-shadow: var(--shadow);
|
||||||
box-shadow: 0 0 2px black inset;
|
background-color: var(--background);
|
||||||
box-shadow: var(--inputShadow);
|
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--input, $fallback--fg);
|
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 1.1em;
|
line-height: 1.1em;
|
||||||
|
@ -80,21 +100,24 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
color: $fallback--faint;
|
color: var(--text);
|
||||||
color: var(--faint, $fallback--faint);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="checkbox"] {
|
input[type="checkbox"] {
|
||||||
&:checked + .checkbox-indicator::before {
|
&:checked + .checkbox-indicator::before {
|
||||||
color: $fallback--text;
|
color: var(--text);
|
||||||
color: var(--inputText, $fallback--text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:indeterminate + .checkbox-indicator::before {
|
&:indeterminate + .checkbox-indicator::before {
|
||||||
content: "–";
|
content: "–";
|
||||||
color: $fallback--text;
|
color: var(--text);
|
||||||
color: var(--inputText, $fallback--text);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.indeterminate-fix {
|
||||||
|
input[type="checkbox"] + .checkbox-indicator::before {
|
||||||
|
content: "–";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
.color-input {
|
.color-input {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|
||||||
|
@ -11,9 +9,8 @@
|
||||||
padding: 0.2em 8px;
|
padding: 0.2em 8px;
|
||||||
|
|
||||||
input {
|
input {
|
||||||
|
color: var(--text);
|
||||||
background: none;
|
background: none;
|
||||||
color: $fallback--lightText;
|
|
||||||
color: var(--inputText, $fallback--lightText);
|
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -23,21 +20,38 @@
|
||||||
min-width: 3em;
|
min-width: 3em;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.nativeColor {
|
.nativeColor {
|
||||||
flex: 0 0 2em;
|
cursor: pointer;
|
||||||
min-width: 2em;
|
flex: 0 0 auto;
|
||||||
align-self: stretch;
|
|
||||||
min-height: 100%;
|
input {
|
||||||
|
appearance: none;
|
||||||
|
max-width: 0;
|
||||||
|
min-width: 0;
|
||||||
|
max-height: 0;
|
||||||
|
/* stylelint-disable-next-line declaration-no-important */
|
||||||
|
opacity: 0 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.computedIndicator,
|
.computedIndicator,
|
||||||
|
.validIndicator,
|
||||||
|
.invalidIndicator,
|
||||||
.transparentIndicator {
|
.transparentIndicator {
|
||||||
flex: 0 0 2em;
|
flex: 0 0 2em;
|
||||||
|
margin: 0 0.5em;
|
||||||
min-width: 2em;
|
min-width: 2em;
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
min-height: 100%;
|
min-height: 1.5em;
|
||||||
|
border-radius: var(--roundness);
|
||||||
|
}
|
||||||
|
|
||||||
|
.invalidIndicator {
|
||||||
|
background: transparent;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 2px solid var(--cRed);
|
||||||
}
|
}
|
||||||
|
|
||||||
.transparentIndicator {
|
.transparentIndicator {
|
||||||
|
@ -58,11 +72,13 @@
|
||||||
&::after {
|
&::after {
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
border-top-left-radius: var(--roundness);
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
border-bottom-right-radius: var(--roundness);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,30 +25,51 @@
|
||||||
:disabled="!present || disabled"
|
:disabled="!present || disabled"
|
||||||
@input="$emit('update:modelValue', $event.target.value)"
|
@input="$emit('update:modelValue', $event.target.value)"
|
||||||
>
|
>
|
||||||
<input
|
<div
|
||||||
v-if="validColor"
|
v-if="validColor"
|
||||||
|
class="validIndicator"
|
||||||
|
:style="{backgroundColor: modelValue || fallback}"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-else-if="transparentColor"
|
||||||
|
class="transparentIndicator"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-else-if="computedColor"
|
||||||
|
class="computedIndicator"
|
||||||
|
:style="{backgroundColor: fallback}"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="invalidIndicator"
|
||||||
|
/>
|
||||||
|
<label class="nativeColor">
|
||||||
|
<FAIcon icon="eye-dropper" />
|
||||||
|
<input
|
||||||
:id="name"
|
:id="name"
|
||||||
class="nativeColor unstyled"
|
class="unstyled"
|
||||||
type="color"
|
type="color"
|
||||||
:value="modelValue || fallback"
|
:value="modelValue || fallback"
|
||||||
:disabled="!present || disabled"
|
:disabled="!present || disabled"
|
||||||
@input="$emit('update:modelValue', $event.target.value)"
|
@input="$emit('update:modelValue', $event.target.value)"
|
||||||
>
|
>
|
||||||
<div
|
</label>
|
||||||
v-if="transparentColor"
|
|
||||||
class="transparentIndicator"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
v-if="computedColor"
|
|
||||||
class="computedIndicator"
|
|
||||||
:style="{backgroundColor: fallback}"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import Checkbox from '../checkbox/checkbox.vue'
|
import Checkbox from '../checkbox/checkbox.vue'
|
||||||
import { hex2rgb } from '../../services/color_convert/color_convert.js'
|
import { hex2rgb } from '../../services/color_convert/color_convert.js'
|
||||||
|
|
||||||
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
import {
|
||||||
|
faEyeDropper
|
||||||
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
library.add(
|
||||||
|
faEyeDropper
|
||||||
|
)
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Checkbox
|
Checkbox
|
||||||
|
@ -108,12 +129,3 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" src="./color_input.scss"></style>
|
<style lang="scss" src="./color_input.scss"></style>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.color-control {
|
|
||||||
input.text-input {
|
|
||||||
max-width: 7em;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -56,7 +56,8 @@ const conversation = {
|
||||||
expanded: false,
|
expanded: false,
|
||||||
threadDisplayStatusObject: {}, // id => 'showing' | 'hidden'
|
threadDisplayStatusObject: {}, // id => 'showing' | 'hidden'
|
||||||
statusContentPropertiesObject: {},
|
statusContentPropertiesObject: {},
|
||||||
inlineDivePosition: null
|
inlineDivePosition: null,
|
||||||
|
loadStatusError: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: [
|
props: [
|
||||||
|
@ -392,11 +393,15 @@ const conversation = {
|
||||||
this.setHighlight(this.originalStatusId)
|
this.setHighlight(this.originalStatusId)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
this.loadStatusError = null
|
||||||
this.$store.state.api.backendInteractor.fetchStatus({ id: this.statusId })
|
this.$store.state.api.backendInteractor.fetchStatus({ id: this.statusId })
|
||||||
.then((status) => {
|
.then((status) => {
|
||||||
this.$store.dispatch('addNewStatuses', { statuses: [status] })
|
this.$store.dispatch('addNewStatuses', { statuses: [status] })
|
||||||
this.fetchConversation()
|
this.fetchConversation()
|
||||||
})
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.loadStatusError = error
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getReplies (id) {
|
getReplies (id) {
|
||||||
|
|
|
@ -28,7 +28,27 @@
|
||||||
class="rightside-button"
|
class="rightside-button"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="conversation-body panel-body">
|
<div
|
||||||
|
v-if="isPage && !status"
|
||||||
|
class="conversation-body"
|
||||||
|
:class="{ 'panel-body': isExpanded }"
|
||||||
|
>
|
||||||
|
<p v-if="!loadStatusError">
|
||||||
|
<FAIcon
|
||||||
|
spin
|
||||||
|
icon="circle-notch"
|
||||||
|
/>
|
||||||
|
{{ $t('status.loading') }}
|
||||||
|
</p>
|
||||||
|
<p v-else>
|
||||||
|
{{ $t('status.load_error', { error: loadStatusError }) }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="conversation-body"
|
||||||
|
:class="{ 'panel-body': isExpanded }"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-if="isTreeView"
|
v-if="isTreeView"
|
||||||
class="thread-body"
|
class="thread-body"
|
||||||
|
@ -203,6 +223,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
|
class="Conversation -hidden"
|
||||||
:style="hiddenStyle"
|
:style="hiddenStyle"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -210,14 +231,17 @@
|
||||||
<script src="./conversation.js"></script>
|
<script src="./conversation.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
.Conversation {
|
.Conversation {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
|
&.-hidden {
|
||||||
|
background: var(--__panel-background);
|
||||||
|
backdrop-filter: var(--__panel-backdrop-filter);
|
||||||
|
}
|
||||||
|
|
||||||
.conversation-dive-to-top-level-box {
|
.conversation-dive-to-top-level-box {
|
||||||
padding: var(--status-margin, $status-margin);
|
padding: var(--status-margin);
|
||||||
border-bottom: 1px solid var(--border, $fallback--border);
|
border-bottom: 1px solid var(--border);
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
|
||||||
/* Make the button stretch along the whole row */
|
/* Make the button stretch along the whole row */
|
||||||
|
@ -227,20 +251,22 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread-ancestors {
|
.thread-ancestors {
|
||||||
margin-left: var(--status-margin, $status-margin);
|
margin-left: var(--status-margin);
|
||||||
border-left: 2px solid var(--border, $fallback--border);
|
border-left: 2px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread-ancestor.-faded .StatusContent {
|
.thread-ancestor.-faded .RichContent {
|
||||||
--link: var(--faintLink);
|
/* stylelint-disable declaration-no-important */
|
||||||
--text: var(--faint);
|
--text: var(--textFaint) !important;
|
||||||
|
--link: var(--linkFaint) !important;
|
||||||
color: var(--text);
|
--funtextGreentext: var(--funtextGreentextFaint) !important;
|
||||||
|
--funtextCyantext: var(--funtextCyantextFaint) !important;
|
||||||
|
/* stylelint-enable declaration-no-important */
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread-ancestor-dive-box {
|
.thread-ancestor-dive-box {
|
||||||
padding-left: var(--status-margin, $status-margin);
|
padding-left: var(--status-margin);
|
||||||
border-bottom: 1px solid var(--border, $fallback--border);
|
border-bottom: 1px solid var(--border);
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
|
||||||
/* Make the button stretch along the whole row */
|
/* Make the button stretch along the whole row */
|
||||||
|
@ -253,16 +279,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread-ancestor-dive-box-inner {
|
.thread-ancestor-dive-box-inner {
|
||||||
padding: var(--status-margin, $status-margin);
|
padding: var(--status-margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
.conversation-status {
|
.conversation-status {
|
||||||
border-bottom: 1px solid var(--border, $fallback--border);
|
border-bottom: 1px solid var(--border);
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread-ancestor-has-other-replies .conversation-status,
|
.thread-ancestor-has-other-replies .conversation-status,
|
||||||
&:last-child .conversation-status,
|
&:last-child:not(.-expanded) .conversation-status,
|
||||||
|
&.-expanded .conversation-status:last-child,
|
||||||
.thread-ancestor:last-child .conversation-status,
|
.thread-ancestor:last-child .conversation-status,
|
||||||
.thread-ancestor:last-child .thread-ancestor-dive-box,
|
.thread-ancestor:last-child .thread-ancestor-dive-box,
|
||||||
&.-expanded .thread-tree .conversation-status {
|
&.-expanded .thread-tree .conversation-status {
|
||||||
|
@ -270,20 +297,36 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread-ancestors + .thread-tree > .conversation-status {
|
.thread-ancestors + .thread-tree > .conversation-status {
|
||||||
border-top: 1px solid var(--border, $fallback--border);
|
border-top: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* expanded conversation in timeline */
|
/* expanded conversation in timeline */
|
||||||
&.status-fadein.-expanded .thread-body {
|
&.status-fadein.-expanded .thread-body {
|
||||||
border-left: 4px solid $fallback--cRed;
|
border-left: 4px solid var(--cRed);
|
||||||
border-left-color: var(--cRed, $fallback--cRed);
|
border-radius: var(--roundness);
|
||||||
border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
|
border-top-left-radius: 0;
|
||||||
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
|
border-top-right-radius: 0;
|
||||||
border-bottom: 1px solid var(--border, $fallback--border);
|
border-bottom: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-expanded.status-fadein {
|
&.-expanded.status-fadein {
|
||||||
margin: calc(var(--status-margin, $status-margin) / 2);
|
--___margin: calc(var(--status-margin) / 2);
|
||||||
|
|
||||||
|
background: var(--background);
|
||||||
|
margin: var(--___margin);
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
z-index: -1;
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: calc(var(--___margin) * -1);
|
||||||
|
bottom: calc(var(--___margin) * -1);
|
||||||
|
left: calc(var(--___margin) * -1);
|
||||||
|
right: calc(var(--___margin) * -1);
|
||||||
|
background: var(--background);
|
||||||
|
backdrop-filter: var(--__panel-backdrop-filter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -14,7 +14,6 @@ import {
|
||||||
faCog,
|
faCog,
|
||||||
faInfoCircle
|
faInfoCircle
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import { useInterfaceStore } from '../../stores/interface'
|
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
faSignInAlt,
|
faSignInAlt,
|
||||||
|
@ -108,7 +107,10 @@ export default {
|
||||||
this.searchBarHidden = hidden
|
this.searchBarHidden = hidden
|
||||||
},
|
},
|
||||||
openSettingsModal () {
|
openSettingsModal () {
|
||||||
useInterfaceStore().openSettingsModal()
|
this.$store.dispatch('openSettingsModal', 'user')
|
||||||
|
},
|
||||||
|
openAdminModal () {
|
||||||
|
this.$store.dispatch('openSettingsModal', 'admin')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
.DesktopNav {
|
.DesktopNav {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: var(--ZI_navbar);
|
z-index: var(--ZI_navbar);
|
||||||
|
@ -9,7 +7,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--topBarLink, $fallback--link);
|
color: var(--link);
|
||||||
}
|
}
|
||||||
|
|
||||||
.inner-nav {
|
.inner-nav {
|
||||||
|
@ -54,27 +52,7 @@
|
||||||
.button-default {
|
.button-default {
|
||||||
&,
|
&,
|
||||||
svg {
|
svg {
|
||||||
color: $fallback--text;
|
color: var(--text);
|
||||||
color: var(--btnTopBarText, $fallback--text);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--btnPressedTopBar, $fallback--fg);
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--btnPressedTopBarText, $fallback--text);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:disabled {
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--btnDisabledTopBarText, $fallback--text);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.toggled {
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--btnToggledTopBarText, $fallback--text);
|
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--btnToggledTopBar, $fallback--fg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,8 +72,7 @@
|
||||||
mask-repeat: no-repeat;
|
mask-repeat: no-repeat;
|
||||||
mask-position: center;
|
mask-position: center;
|
||||||
mask-size: contain;
|
mask-size: contain;
|
||||||
background-color: $fallback--fg;
|
background-color: var(--text);
|
||||||
background-color: var(--topBarText, $fallback--fg);
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
@ -116,8 +93,7 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
.svg-inline--fa {
|
.svg-inline--fa {
|
||||||
color: $fallback--link;
|
color: var(--link);
|
||||||
color: var(--topBarLink, $fallback--link);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,20 +48,19 @@
|
||||||
icon="cog"
|
icon="cog"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<a
|
<button
|
||||||
v-if="currentUser && currentUser.role === 'admin'"
|
v-if="currentUser && currentUser.role === 'admin'"
|
||||||
href="/pleroma/admin/#/login-pleroma"
|
class="button-unstyled nav-icon"
|
||||||
class="nav-icon"
|
|
||||||
target="_blank"
|
target="_blank"
|
||||||
:title="$t('nav.administration')"
|
:title="$t('nav.administration')"
|
||||||
@click.stop
|
@click.stop="openAdminModal"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
fixed-width
|
fixed-width
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110 fa-old-padding"
|
||||||
icon="tachometer-alt"
|
icon="tachometer-alt"
|
||||||
/>
|
/>
|
||||||
</a>
|
</button>
|
||||||
<span class="spacer" />
|
<span class="spacer" />
|
||||||
<button
|
<button
|
||||||
v-if="currentUser"
|
v-if="currentUser"
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<slot name="header" />
|
<slot name="header" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dialog-modal-content">
|
<div class="panel-body dialog-modal-content">
|
||||||
<slot name="default" />
|
<slot name="default" />
|
||||||
</div>
|
</div>
|
||||||
<div class="dialog-modal-footer user-interactions panel-footer">
|
<div class="dialog-modal-footer user-interactions panel-footer">
|
||||||
|
@ -25,8 +25,6 @@
|
||||||
<script src="./dialog_modal.js"></script>
|
<script src="./dialog_modal.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
// TODO: unify with other modals.
|
// TODO: unify with other modals.
|
||||||
.dark-overlay {
|
.dark-overlay {
|
||||||
&::before {
|
&::before {
|
||||||
|
@ -54,8 +52,6 @@
|
||||||
z-index: 2001;
|
z-index: 2001;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
display: block;
|
display: block;
|
||||||
background-color: $fallback--bg;
|
|
||||||
background-color: var(--bg, $fallback--bg);
|
|
||||||
|
|
||||||
.dialog-modal-heading {
|
.dialog-modal-heading {
|
||||||
.title {
|
.title {
|
||||||
|
@ -66,18 +62,13 @@
|
||||||
.dialog-modal-content {
|
.dialog-modal-content {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background-color: $fallback--bg;
|
|
||||||
background-color: var(--bg, $fallback--bg);
|
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-modal-footer {
|
.dialog-modal-footer {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
background-color: $fallback--bg;
|
border-top: 1px solid var(--border);
|
||||||
background-color: var(--bg, $fallback--bg);
|
|
||||||
border-top: 1px solid $fallback--border;
|
|
||||||
border-top: 1px solid var(--border, $fallback--border);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ import PostStatusForm from '../post_status_form/post_status_form.vue'
|
||||||
import Modal from '../modal/modal.vue'
|
import Modal from '../modal/modal.vue'
|
||||||
import statusPosterService from '../../services/status_poster/status_poster.service.js'
|
import statusPosterService from '../../services/status_poster/status_poster.service.js'
|
||||||
import get from 'lodash/get'
|
import get from 'lodash/get'
|
||||||
import { useEditStatusStore } from '../../stores/editStatus'
|
|
||||||
|
|
||||||
const EditStatusModal = {
|
const EditStatusModal = {
|
||||||
components: {
|
components: {
|
||||||
|
@ -19,13 +18,13 @@ const EditStatusModal = {
|
||||||
return !!this.$store.state.users.currentUser
|
return !!this.$store.state.users.currentUser
|
||||||
},
|
},
|
||||||
modalActivated () {
|
modalActivated () {
|
||||||
return useEditStatusStore().modalActivated
|
return this.$store.state.editStatus.modalActivated
|
||||||
},
|
},
|
||||||
isFormVisible () {
|
isFormVisible () {
|
||||||
return this.isLoggedIn && !this.resettingForm && this.modalActivated
|
return this.isLoggedIn && !this.resettingForm && this.modalActivated
|
||||||
},
|
},
|
||||||
params () {
|
params () {
|
||||||
return useEditStatusStore().params || {}
|
return this.$store.state.editStatus.params || {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -47,7 +46,7 @@ const EditStatusModal = {
|
||||||
doEditStatus ({ status, spoilerText, sensitive, media, contentType, poll }) {
|
doEditStatus ({ status, spoilerText, sensitive, media, contentType, poll }) {
|
||||||
const params = {
|
const params = {
|
||||||
store: this.$store,
|
store: this.$store,
|
||||||
statusId: useEditStatusStore().params.statusId,
|
statusId: this.$store.state.editStatus.params.statusId,
|
||||||
status,
|
status,
|
||||||
spoilerText,
|
spoilerText,
|
||||||
sensitive,
|
sensitive,
|
||||||
|
@ -68,7 +67,7 @@ const EditStatusModal = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
closeModal () {
|
closeModal () {
|
||||||
useEditStatusStore().closeEditStatusModal()
|
this.$store.dispatch('closeEditStatusModal')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Completion from '../../services/completion/completion.js'
|
import Completion from '../../services/completion/completion.js'
|
||||||
|
import genRandomSeed from '../../services/random_seed/random_seed.service.js'
|
||||||
import EmojiPicker from '../emoji_picker/emoji_picker.vue'
|
import EmojiPicker from '../emoji_picker/emoji_picker.vue'
|
||||||
import Popover from 'src/components/popover/popover.vue'
|
import Popover from 'src/components/popover/popover.vue'
|
||||||
import ScreenReaderNotice from 'src/components/screen_reader_notice/screen_reader_notice.vue'
|
import ScreenReaderNotice from 'src/components/screen_reader_notice/screen_reader_notice.vue'
|
||||||
|
@ -110,7 +111,7 @@ const EmojiInput = {
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
randomSeed: `${Math.random()}`.replace('.', '-'),
|
randomSeed: genRandomSeed(),
|
||||||
input: undefined,
|
input: undefined,
|
||||||
caretEl: undefined,
|
caretEl: undefined,
|
||||||
highlighted: -1,
|
highlighted: -1,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
ref="root"
|
ref="root"
|
||||||
class="emoji-input"
|
class="input emoji-input"
|
||||||
:class="{ 'with-picker': !hideEmojiButton }"
|
:class="{ 'with-picker': !hideEmojiButton }"
|
||||||
>
|
>
|
||||||
<slot
|
<slot
|
||||||
|
@ -68,9 +68,9 @@
|
||||||
v-for="(suggestion, index) in suggestions"
|
v-for="(suggestion, index) in suggestions"
|
||||||
:id="suggestionItemId(index)"
|
:id="suggestionItemId(index)"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="autocomplete-item"
|
class="menu-item autocomplete-item"
|
||||||
role="option"
|
role="option"
|
||||||
:class="{ highlighted: index === highlighted }"
|
:class="{ '-active': index === highlighted }"
|
||||||
:aria-label="autoCompleteItemLabel(suggestion)"
|
:aria-label="autoCompleteItemLabel(suggestion)"
|
||||||
:aria-selected="index === highlighted"
|
:aria-selected="index === highlighted"
|
||||||
@click.stop.prevent="onClick($event, suggestion)"
|
@click.stop.prevent="onClick($event, suggestion)"
|
||||||
|
@ -110,9 +110,8 @@
|
||||||
<script src="./emoji_input.js"></script>
|
<script src="./emoji_input.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
.input.emoji-input {
|
||||||
|
padding: 0;
|
||||||
.emoji-input {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -127,8 +126,7 @@
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
|
|
||||||
&:hover i {
|
&:hover i {
|
||||||
color: $fallback--text;
|
color: var(--text);
|
||||||
color: var(--text, $fallback--text);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +143,12 @@
|
||||||
input,
|
input,
|
||||||
textarea {
|
textarea {
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
|
color: inherit;
|
||||||
|
/* stylelint-disable-next-line declaration-no-important */
|
||||||
|
background: none !important;
|
||||||
|
box-shadow: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.with-picker input {
|
&.with-picker input {
|
||||||
|
@ -179,26 +183,28 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-item {
|
&-item.menu-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
cursor: pointer;
|
padding-top: 0;
|
||||||
padding: 0.2em 0.4em;
|
padding-bottom: 0;
|
||||||
border-bottom: 1px solid rgb(0 0 0 / 40%);
|
|
||||||
height: 32px;
|
|
||||||
|
|
||||||
.image {
|
.image {
|
||||||
width: 32px;
|
width: calc(var(--__line-height) + var(--__vertical-gap) * 2);
|
||||||
height: 32px;
|
height: calc(var(--__line-height) + var(--__vertical-gap) * 2);
|
||||||
line-height: 32px;
|
line-height: var(--__line-height);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 32px;
|
margin-right: var(--__horizontal-gap);
|
||||||
margin-right: 4px;
|
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 32px;
|
width: calc(var(--__line-height) + var(--__vertical-gap) * 2);
|
||||||
height: 32px;
|
height: calc(var(--__line-height) + var(--__vertical-gap) * 2);
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: var(--__line-height);
|
||||||
|
line-height: var(--__line-height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
|
@ -216,17 +222,6 @@
|
||||||
line-height: 9px;
|
line-height: 9px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.highlighted {
|
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--selectedMenuPopover, $fallback--fg);
|
|
||||||
color: var(--selectedMenuPopoverText, $fallback--text);
|
|
||||||
|
|
||||||
--faint: var(--selectedMenuPopoverFaintText, $fallback--faint);
|
|
||||||
--faintLink: var(--selectedMenuPopoverFaintLink, $fallback--faint);
|
|
||||||
--lightText: var(--selectedMenuPopoverLightText, $fallback--lightText);
|
|
||||||
--icon: var(--selectedMenuPopoverIcon, $fallback--icon);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -105,6 +105,7 @@ const EmojiPicker = {
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
inject: ['popoversZLayer'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
keyword: '',
|
keyword: '',
|
||||||
|
@ -113,6 +114,7 @@ const EmojiPicker = {
|
||||||
groupsScrolledClass: 'scrolled-top',
|
groupsScrolledClass: 'scrolled-top',
|
||||||
keepOpen: false,
|
keepOpen: false,
|
||||||
customEmojiTimeout: null,
|
customEmojiTimeout: null,
|
||||||
|
hideCustomEmojiInPicker: false,
|
||||||
// Lazy-load only after the first time `showing` becomes true.
|
// Lazy-load only after the first time `showing` becomes true.
|
||||||
contentLoaded: false,
|
contentLoaded: false,
|
||||||
groupRefs: {},
|
groupRefs: {},
|
||||||
|
@ -285,7 +287,7 @@ const EmojiPicker = {
|
||||||
return 0
|
return 0
|
||||||
},
|
},
|
||||||
allCustomGroups () {
|
allCustomGroups () {
|
||||||
if (this.hideCustomEmoji) {
|
if (this.hideCustomEmoji || this.hideCustomEmojiInPicker) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
const emojis = this.$store.getters.groupedCustomEmojis
|
const emojis = this.$store.getters.groupedCustomEmojis
|
||||||
|
@ -350,6 +352,9 @@ const EmojiPicker = {
|
||||||
|
|
||||||
return emoji.displayText
|
return emoji.displayText
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
isInModal () {
|
||||||
|
return this.popoversZLayer === 'modals'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
$emoji-picker-header-height: 36px;
|
$emoji-picker-header-height: 36px;
|
||||||
$emoji-picker-header-picture-width: 32px;
|
$emoji-picker-header-picture-width: 32px;
|
||||||
$emoji-picker-header-picture-height: 32px;
|
$emoji-picker-header-picture-height: 32px;
|
||||||
|
@ -10,15 +8,6 @@ $emoji-picker-emoji-size: 32px;
|
||||||
max-width: calc(100vw - 20px); // popover gives 10px margin from window edge
|
max-width: calc(100vw - 20px); // popover gives 10px margin from window edge
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background-color: $fallback--bg;
|
|
||||||
background-color: var(--popover, $fallback--bg);
|
|
||||||
color: $fallback--link;
|
|
||||||
color: var(--popoverText, $fallback--link);
|
|
||||||
|
|
||||||
--faint: var(--popoverFaintText, $fallback--faint);
|
|
||||||
--faintLink: var(--popoverFaintLink, $fallback--faint);
|
|
||||||
--lightText: var(--popoverLightText, $fallback--lightText);
|
|
||||||
--icon: var(--popoverIcon, $fallback--icon);
|
|
||||||
|
|
||||||
&-header-image {
|
&-header-image {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
@ -39,11 +28,16 @@ $emoji-picker-emoji-size: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.keep-open,
|
.keep-open,
|
||||||
.too-many-emoji {
|
.too-many-emoji,
|
||||||
|
.hide-custom-emoji {
|
||||||
padding: 7px;
|
padding: 7px;
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hide-custom-emoji {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.too-many-emoji {
|
.too-many-emoji {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -76,8 +70,7 @@ $emoji-picker-emoji-size: 32px;
|
||||||
.additional-tabs {
|
.additional-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
border-left: 1px solid;
|
border-left: 1px solid;
|
||||||
border-left-color: $fallback--icon;
|
border-left-color: var(--border);
|
||||||
border-left-color: var(--icon, $fallback--icon);
|
|
||||||
padding-left: 7px;
|
padding-left: 7px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
@ -104,13 +97,8 @@ $emoji-picker-emoji-size: 32px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.toggled {
|
||||||
border-bottom: 4px solid;
|
border-bottom: 4px solid;
|
||||||
|
|
||||||
svg {
|
|
||||||
color: $fallback--lightText;
|
|
||||||
color: var(--lightText, $fallback--lightText);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,25 +3,32 @@
|
||||||
ref="popover"
|
ref="popover"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
popover-class="emoji-picker popover-default"
|
popover-class="emoji-picker popover-default"
|
||||||
:trigger-attrs="{ 'aria-hidden': true }"
|
:trigger-attrs="{ 'aria-hidden': true, tabindex: -1 }"
|
||||||
@show="onPopoverShown"
|
@show="onPopoverShown"
|
||||||
@close="onPopoverClosed"
|
@close="onPopoverClosed"
|
||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="heading">
|
<div class="heading">
|
||||||
|
<!--
|
||||||
|
Body scroll lock needs to be on every scrollable element on safari iOS.
|
||||||
|
Here we tell it to enable scrolling for this element.
|
||||||
|
See https://github.com/willmcpo/body-scroll-lock#vanilla-js
|
||||||
|
-->
|
||||||
<span
|
<span
|
||||||
ref="header"
|
ref="header"
|
||||||
|
v-body-scroll-lock="isInModal"
|
||||||
class="emoji-tabs"
|
class="emoji-tabs"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
v-for="group in filteredEmojiGroups"
|
v-for="group in filteredEmojiGroups"
|
||||||
:ref="setGroupRef('group-header-' + group.id)"
|
:ref="setGroupRef('group-header-' + group.id)"
|
||||||
:key="group.id"
|
:key="group.id"
|
||||||
class="emoji-tabs-item"
|
class="button-unstyled emoji-tabs-item"
|
||||||
:class="{
|
:class="{
|
||||||
active: activeGroupView === group.id
|
toggled: activeGroupView === group.id
|
||||||
}"
|
}"
|
||||||
:title="group.text"
|
:title="group.text"
|
||||||
|
role="button"
|
||||||
@click.prevent="highlight(group.id)"
|
@click.prevent="highlight(group.id)"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
@ -45,8 +52,8 @@
|
||||||
class="additional-tabs"
|
class="additional-tabs"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="stickers-tab-icon additional-tabs-item"
|
class="button-unstyled stickers-tab-icon additional-tabs-item"
|
||||||
:class="{active: showingStickers}"
|
:class="{toggled: showingStickers}"
|
||||||
:title="$t('emoji.stickers')"
|
:title="$t('emoji.stickers')"
|
||||||
@click.prevent="toggleStickers"
|
@click.prevent="toggleStickers"
|
||||||
>
|
>
|
||||||
|
@ -70,13 +77,15 @@
|
||||||
ref="search"
|
ref="search"
|
||||||
v-model="keyword"
|
v-model="keyword"
|
||||||
type="text"
|
type="text"
|
||||||
class="form-control"
|
class="input form-control"
|
||||||
:placeholder="$t('emoji.search_emoji')"
|
:placeholder="$t('emoji.search_emoji')"
|
||||||
@input="$event.target.composing = false"
|
@input="$event.target.composing = false"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Enables scrolling for this element on safari iOS. See comments for header. -->
|
||||||
<DynamicScroller
|
<DynamicScroller
|
||||||
ref="emoji-groups"
|
ref="emoji-groups"
|
||||||
|
v-body-scroll-lock="isInModal"
|
||||||
class="emoji-groups"
|
class="emoji-groups"
|
||||||
:class="groupsScrolledClass"
|
:class="groupsScrolledClass"
|
||||||
:min-item-size="minItemSize"
|
:min-item-size="minItemSize"
|
||||||
|
@ -108,6 +117,7 @@
|
||||||
:key="group.id + emoji.displayText"
|
:key="group.id + emoji.displayText"
|
||||||
:title="maybeLocalizedEmojiName(emoji)"
|
:title="maybeLocalizedEmojiName(emoji)"
|
||||||
class="emoji-item"
|
class="emoji-item"
|
||||||
|
role="button"
|
||||||
@click.stop.prevent="onEmoji(emoji)"
|
@click.stop.prevent="onEmoji(emoji)"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
@ -118,6 +128,7 @@
|
||||||
v-else
|
v-else
|
||||||
class="emoji-picker-emoji -custom"
|
class="emoji-picker-emoji -custom"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
|
:alt="maybeLocalizedEmojiName(emoji)"
|
||||||
:src="emoji.imageUrl"
|
:src="emoji.imageUrl"
|
||||||
:data-emoji-name="group.id + emoji.displayText"
|
:data-emoji-name="group.id + emoji.displayText"
|
||||||
/>
|
/>
|
||||||
|
@ -131,6 +142,17 @@
|
||||||
{{ $t('emoji.keep_open') }}
|
{{ $t('emoji.keep_open') }}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="!hideCustomEmoji"
|
||||||
|
class="hide-custom-emoji"
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
v-model="hideCustomEmojiInPicker"
|
||||||
|
@change="onShowing"
|
||||||
|
>
|
||||||
|
{{ $t('emoji.hide_custom_emoji') }}
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="showingStickers"
|
v-if="showingStickers"
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||||
import UserListPopover from '../user_list_popover/user_list_popover.vue'
|
import UserListPopover from '../user_list_popover/user_list_popover.vue'
|
||||||
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
import {
|
||||||
|
faPlus,
|
||||||
|
faMinus,
|
||||||
|
faCheck
|
||||||
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
library.add(
|
||||||
|
faPlus,
|
||||||
|
faMinus,
|
||||||
|
faCheck
|
||||||
|
)
|
||||||
|
|
||||||
const EMOJI_REACTION_COUNT_CUTOFF = 12
|
const EMOJI_REACTION_COUNT_CUTOFF = 12
|
||||||
|
|
||||||
|
@ -33,6 +45,9 @@ const EmojiReactions = {
|
||||||
},
|
},
|
||||||
loggedIn () {
|
loggedIn () {
|
||||||
return !!this.$store.state.users.currentUser
|
return !!this.$store.state.users.currentUser
|
||||||
|
},
|
||||||
|
remoteInteractionLink () {
|
||||||
|
return this.$store.getters.remoteInteractionLink({ statusId: this.status.id })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -42,10 +57,10 @@ const EmojiReactions = {
|
||||||
reactedWith (emoji) {
|
reactedWith (emoji) {
|
||||||
return this.status.emoji_reactions.find(r => r.name === emoji).me
|
return this.status.emoji_reactions.find(r => r.name === emoji).me
|
||||||
},
|
},
|
||||||
fetchEmojiReactionsByIfMissing () {
|
async fetchEmojiReactionsByIfMissing () {
|
||||||
const hasNoAccounts = this.status.emoji_reactions.find(r => !r.accounts)
|
const hasNoAccounts = this.status.emoji_reactions.find(r => !r.accounts)
|
||||||
if (hasNoAccounts) {
|
if (hasNoAccounts) {
|
||||||
this.$store.dispatch('fetchEmojiReactionsBy', this.status.id)
|
return await this.$store.dispatch('fetchEmojiReactionsBy', this.status.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
reactWith (emoji) {
|
reactWith (emoji) {
|
||||||
|
@ -54,14 +69,26 @@ const EmojiReactions = {
|
||||||
unreact (emoji) {
|
unreact (emoji) {
|
||||||
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
|
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
|
||||||
},
|
},
|
||||||
emojiOnClick (emoji, event) {
|
async emojiOnClick (emoji, event) {
|
||||||
if (!this.loggedIn) return
|
if (!this.loggedIn) return
|
||||||
|
|
||||||
|
await this.fetchEmojiReactionsByIfMissing()
|
||||||
if (this.reactedWith(emoji)) {
|
if (this.reactedWith(emoji)) {
|
||||||
this.unreact(emoji)
|
this.unreact(emoji)
|
||||||
} else {
|
} else {
|
||||||
this.reactWith(emoji)
|
this.reactWith(emoji)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
counterTriggerAttrs (reaction) {
|
||||||
|
return {
|
||||||
|
class: [
|
||||||
|
'btn',
|
||||||
|
'button-default',
|
||||||
|
'emoji-reaction-count-button',
|
||||||
|
{ '-picked-reaction': this.reactedWith(reaction.name) }
|
||||||
|
],
|
||||||
|
'aria-label': this.$tc('status.reaction_count_label', reaction.count, { num: reaction.count })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="EmojiReactions">
|
<div class="EmojiReactions">
|
||||||
<UserListPopover
|
<span
|
||||||
v-for="(reaction) in emojiReactions"
|
v-for="(reaction) in emojiReactions"
|
||||||
:key="reaction.url || reaction.name"
|
:key="reaction.url || reaction.name"
|
||||||
:users="accountsForEmoji[reaction.name]"
|
class="emoji-reaction-container btn-group"
|
||||||
>
|
>
|
||||||
<button
|
<component
|
||||||
|
:is="loggedIn ? 'button' : 'a'"
|
||||||
|
v-bind="!loggedIn ? { href: remoteInteractionLink } : {}"
|
||||||
|
role="button"
|
||||||
class="emoji-reaction btn button-default"
|
class="emoji-reaction btn button-default"
|
||||||
:class="{ '-picked-reaction': reactedWith(reaction.name), 'not-clickable': !loggedIn }"
|
:class="{ '-picked-reaction': reactedWith(reaction.name) }"
|
||||||
|
:title="reaction.url ? reaction.name : undefined"
|
||||||
|
:aria-pressed="reactedWith(reaction.name)"
|
||||||
@click="emojiOnClick(reaction.name, $event)"
|
@click="emojiOnClick(reaction.name, $event)"
|
||||||
@mouseenter="fetchEmojiReactionsByIfMissing()"
|
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="reaction-emoji"
|
class="reaction-emoji"
|
||||||
|
@ -17,7 +21,6 @@
|
||||||
<img
|
<img
|
||||||
v-if="reaction.url"
|
v-if="reaction.url"
|
||||||
:src="reaction.url"
|
:src="reaction.url"
|
||||||
:title="reaction.name"
|
|
||||||
class="reaction-emoji-content"
|
class="reaction-emoji-content"
|
||||||
width="1em"
|
width="1em"
|
||||||
>
|
>
|
||||||
|
@ -26,9 +29,36 @@
|
||||||
class="reaction-emoji reaction-emoji-content"
|
class="reaction-emoji reaction-emoji-content"
|
||||||
>{{ reaction.name }}</span>
|
>{{ reaction.name }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span>{{ reaction.count }}</span>
|
<FALayers>
|
||||||
</button>
|
<FAIcon
|
||||||
|
v-if="reactedWith(reaction.name)"
|
||||||
|
class="active-marker"
|
||||||
|
transform="shrink-6 up-9"
|
||||||
|
icon="check"
|
||||||
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-if="!reactedWith(reaction.name)"
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-9"
|
||||||
|
icon="plus"
|
||||||
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-else
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-9"
|
||||||
|
icon="minus"
|
||||||
|
/>
|
||||||
|
</FALayers>
|
||||||
|
</component>
|
||||||
|
<UserListPopover
|
||||||
|
:users="accountsForEmoji[reaction.name]"
|
||||||
|
class="emoji-reaction-popover"
|
||||||
|
:trigger-attrs="counterTriggerAttrs(reaction)"
|
||||||
|
@show="fetchEmojiReactionsByIfMissing()"
|
||||||
|
>
|
||||||
|
<span class="emoji-reaction-counts">{{ reaction.count }}</span>
|
||||||
</UserListPopover>
|
</UserListPopover>
|
||||||
|
</span>
|
||||||
<a
|
<a
|
||||||
v-if="tooManyReactions"
|
v-if="tooManyReactions"
|
||||||
class="emoji-reaction-expand faint"
|
class="emoji-reaction-expand faint"
|
||||||
|
@ -42,7 +72,7 @@
|
||||||
|
|
||||||
<script src="./emoji_reactions.js"></script>
|
<script src="./emoji_reactions.js"></script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
@import "../../mixins";
|
||||||
|
|
||||||
.EmojiReactions {
|
.EmojiReactions {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -51,14 +81,43 @@
|
||||||
|
|
||||||
--emoji-size: calc(1.25em * var(--emojiReactionsScale, 1));
|
--emoji-size: calc(1.25em * var(--emojiReactionsScale, 1));
|
||||||
|
|
||||||
.emoji-reaction {
|
.emoji-reaction-container {
|
||||||
padding: 0 0.5em;
|
display: flex;
|
||||||
margin-right: 0.5em;
|
align-items: stretch;
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
|
||||||
|
.emoji-reaction-popover {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.emoji-reaction-count-button {
|
||||||
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
min-width: 2em;
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&.-picked-reaction {
|
||||||
|
border: 1px solid var(--accent);
|
||||||
|
margin-right: -1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-reaction {
|
||||||
|
padding-left: 0.5em;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
.reaction-emoji {
|
.reaction-emoji {
|
||||||
width: var(--emoji-size);
|
width: var(--emoji-size);
|
||||||
|
@ -85,19 +144,42 @@
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.not-clickable {
|
.svg-inline--fa {
|
||||||
cursor: default;
|
color: var(--text);
|
||||||
|
|
||||||
&:hover {
|
|
||||||
box-shadow: $fallback--buttonShadow;
|
|
||||||
box-shadow: var(--buttonShadow);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-picked-reaction {
|
&.-picked-reaction {
|
||||||
border: 1px solid var(--accent, $fallback--link);
|
border: 1px solid var(--accent);
|
||||||
margin-left: -1px; // offset the border, can't use inset shadows either
|
margin-left: -1px; // offset the border, can't use inset shadows either
|
||||||
margin-right: calc(0.5em - 1px);
|
margin-right: -1px;
|
||||||
|
|
||||||
|
.svg-inline--fa {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include unfocused-style {
|
||||||
|
.focus-marker {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-marker {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include focused-style {
|
||||||
|
.svg-inline--fa {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.focus-marker {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-marker {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Popover from '../popover/popover.vue'
|
import Popover from '../popover/popover.vue'
|
||||||
|
import genRandomSeed from '../../services/random_seed/random_seed.service.js'
|
||||||
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
|
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
@ -16,9 +17,6 @@ import {
|
||||||
faBookmark as faBookmarkReg,
|
faBookmark as faBookmarkReg,
|
||||||
faFlag
|
faFlag
|
||||||
} from '@fortawesome/free-regular-svg-icons'
|
} from '@fortawesome/free-regular-svg-icons'
|
||||||
import { useEditStatusStore } from '../../stores/editStatus'
|
|
||||||
import { useStatusHistoryStore } from '../../stores/statusHistory'
|
|
||||||
import { useReportsStore } from '../../stores/reports'
|
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
faEllipsisH,
|
faEllipsisH,
|
||||||
|
@ -43,7 +41,8 @@ const ExtraButtons = {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
expanded: false,
|
expanded: false,
|
||||||
showingDeleteDialog: false
|
showingDeleteDialog: false,
|
||||||
|
randomSeed: genRandomSeed()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -106,11 +105,11 @@ const ExtraButtons = {
|
||||||
.catch(err => this.$emit('onError', err.error.error))
|
.catch(err => this.$emit('onError', err.error.error))
|
||||||
},
|
},
|
||||||
reportStatus () {
|
reportStatus () {
|
||||||
useReportsStore().openUserReportingModal({ userId: this.status.user.id, statusIds: [this.status.id] })
|
this.$store.dispatch('openUserReportingModal', { userId: this.status.user.id, statusIds: [this.status.id] })
|
||||||
},
|
},
|
||||||
editStatus () {
|
editStatus () {
|
||||||
this.$store.dispatch('fetchStatusSource', { id: this.status.id })
|
this.$store.dispatch('fetchStatusSource', { id: this.status.id })
|
||||||
.then(data => useEditStatusStore().openEditStatusModal({
|
.then(data => this.$store.dispatch('openEditStatusModal', {
|
||||||
statusId: this.status.id,
|
statusId: this.status.id,
|
||||||
subject: data.spoiler_text,
|
subject: data.spoiler_text,
|
||||||
statusText: data.text,
|
statusText: data.text,
|
||||||
|
@ -125,7 +124,7 @@ const ExtraButtons = {
|
||||||
const originalStatus = { ...this.status }
|
const originalStatus = { ...this.status }
|
||||||
const stripFieldsList = ['attachments', 'created_at', 'emojis', 'text', 'raw_html', 'nsfw', 'poll', 'summary', 'summary_raw_html']
|
const stripFieldsList = ['attachments', 'created_at', 'emojis', 'text', 'raw_html', 'nsfw', 'poll', 'summary', 'summary_raw_html']
|
||||||
stripFieldsList.forEach(p => delete originalStatus[p])
|
stripFieldsList.forEach(p => delete originalStatus[p])
|
||||||
useStatusHistoryStore().openStatusHistoryModal(originalStatus)
|
this.$store.dispatch('openStatusHistoryModal', originalStatus)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -155,6 +154,15 @@ const ExtraButtons = {
|
||||||
editingAvailable () { return this.$store.state.instance.editingAvailable },
|
editingAvailable () { return this.$store.state.instance.editingAvailable },
|
||||||
shouldConfirmDelete () {
|
shouldConfirmDelete () {
|
||||||
return this.$store.getters.mergedConfig.modalOnDelete
|
return this.$store.getters.mergedConfig.modalOnDelete
|
||||||
|
},
|
||||||
|
triggerAttrs () {
|
||||||
|
return {
|
||||||
|
title: this.$t('status.more_actions'),
|
||||||
|
id: `popup-trigger-${this.randomSeed}`,
|
||||||
|
'aria-controls': `popup-menu-${this.randomSeed}`,
|
||||||
|
'aria-expanded': this.expanded,
|
||||||
|
'aria-haspopup': 'menu'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<Popover
|
<Popover
|
||||||
class="ExtraButtons"
|
class="ExtraButtons"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
|
:trigger-attrs="triggerAttrs"
|
||||||
placement="top"
|
placement="top"
|
||||||
:offset="{ y: 5 }"
|
:offset="{ y: 5 }"
|
||||||
:bound-to="{ x: 'container' }"
|
:bound-to="{ x: 'container' }"
|
||||||
|
@ -10,10 +11,15 @@
|
||||||
@close="onClose"
|
@close="onClose"
|
||||||
>
|
>
|
||||||
<template #content="{close}">
|
<template #content="{close}">
|
||||||
<div class="dropdown-menu">
|
<div
|
||||||
|
:id="`popup-menu-${randomSeed}`"
|
||||||
|
class="dropdown-menu"
|
||||||
|
role="menu"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
v-if="canMute && !status.thread_muted"
|
v-if="canMute && !status.thread_muted"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
|
role="menuitem"
|
||||||
@click.prevent="muteConversation"
|
@click.prevent="muteConversation"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -23,7 +29,8 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="canMute && status.thread_muted"
|
v-if="canMute && status.thread_muted"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
|
role="menuitem"
|
||||||
@click.prevent="unmuteConversation"
|
@click.prevent="unmuteConversation"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -33,7 +40,8 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="!status.pinned && canPin"
|
v-if="!status.pinned && canPin"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
|
role="menuitem"
|
||||||
@click.prevent="pinStatus"
|
@click.prevent="pinStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -44,7 +52,8 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="status.pinned && canPin"
|
v-if="status.pinned && canPin"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
|
role="menuitem"
|
||||||
@click.prevent="unpinStatus"
|
@click.prevent="unpinStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -56,7 +65,8 @@
|
||||||
<template v-if="canBookmark">
|
<template v-if="canBookmark">
|
||||||
<button
|
<button
|
||||||
v-if="!status.bookmarked"
|
v-if="!status.bookmarked"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
|
role="menuitem"
|
||||||
@click.prevent="bookmarkStatus"
|
@click.prevent="bookmarkStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -67,7 +77,8 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="status.bookmarked"
|
v-if="status.bookmarked"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
|
role="menuitem"
|
||||||
@click.prevent="unbookmarkStatus"
|
@click.prevent="unbookmarkStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -79,7 +90,8 @@
|
||||||
</template>
|
</template>
|
||||||
<button
|
<button
|
||||||
v-if="ownStatus && editingAvailable"
|
v-if="ownStatus && editingAvailable"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
|
role="menuitem"
|
||||||
@click.prevent="editStatus"
|
@click.prevent="editStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -90,7 +102,8 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="isEdited && editingAvailable"
|
v-if="isEdited && editingAvailable"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
|
role="menuitem"
|
||||||
@click.prevent="showStatusHistory"
|
@click.prevent="showStatusHistory"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -101,7 +114,8 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="canDelete"
|
v-if="canDelete"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
|
role="menuitem"
|
||||||
@click.prevent="deleteStatus"
|
@click.prevent="deleteStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -111,7 +125,8 @@
|
||||||
/><span>{{ $t("status.delete") }}</span>
|
/><span>{{ $t("status.delete") }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
|
role="menuitem"
|
||||||
@click.prevent="copyLink"
|
@click.prevent="copyLink"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -122,7 +137,8 @@
|
||||||
</button>
|
</button>
|
||||||
<a
|
<a
|
||||||
v-if="!status.is_local"
|
v-if="!status.is_local"
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
|
role="menuitem"
|
||||||
title="Source"
|
title="Source"
|
||||||
:href="status.external_url"
|
:href="status.external_url"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
@ -133,7 +149,8 @@
|
||||||
/><span>{{ $t("status.external_source") }}</span>
|
/><span>{{ $t("status.external_source") }}</span>
|
||||||
</a>
|
</a>
|
||||||
<button
|
<button
|
||||||
class="button-default dropdown-item dropdown-item-icon"
|
class="menu-item dropdown-item dropdown-item-icon"
|
||||||
|
role="menuitem"
|
||||||
@click.prevent="reportStatus"
|
@click.prevent="reportStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -184,7 +201,6 @@
|
||||||
<script src="./extra_buttons.js"></script>
|
<script src="./extra_buttons.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../variables";
|
|
||||||
@import "../../mixins";
|
@import "../../mixins";
|
||||||
|
|
||||||
.ExtraButtons {
|
.ExtraButtons {
|
||||||
|
@ -194,8 +210,7 @@
|
||||||
margin: -10px;
|
margin: -10px;
|
||||||
|
|
||||||
&:hover .svg-inline--fa {
|
&:hover .svg-inline--fa {
|
||||||
color: $fallback--text;
|
color: var(--text);
|
||||||
color: var(--text, $fallback--text);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue