Compare commits

..

414 Commits

Author SHA1 Message Date
Shpuld Shpludson b13d8f7e63 Merge branch 'develop' into 'master'
Update MASTER for 2.4.2

See merge request pleroma/pleroma-fe!1421
2022-01-09 18:37:01 +00:00
Shpuld Shpludson 756f7bf7c2 Merge branch 'shpuld-develop-patch-58245' into 'develop'
Update CHANGELOG.md

See merge request pleroma/pleroma-fe!1423
2022-01-09 18:29:46 +00:00
Shpuld Shpludson 4cd27acf7f Update CHANGELOG.md 2022-01-09 18:26:35 +00:00
Shpuld Shpludson 030c374def Merge branch 'shpuld-develop-patch-87791' into 'develop'
Update CHANGELOG.md

See merge request pleroma/pleroma-fe!1422
2022-01-09 18:21:14 +00:00
Shpuld Shpludson 056f5f547a Update CHANGELOG.md 2022-01-09 18:16:44 +00:00
HJ d22e04eaf6 Merge branch 'allow_to_cancel_follow_request' into 'develop'
Allow canceling a follow request

See merge request pleroma/pleroma-fe!1416
2021-12-28 11:43:24 +00:00
Ilja 4587f37dd7 Allow canceling a follow request
When a follow request is sent, but not (yet) accepted, the behaviour is now to cancel the request instead of re sending.

The reason is double
* You couldn't cancel a follow request if you change your mind and the request wasn't answered yet
* Instances don't always correctly process a new follow request when the following is already happening. If something went wrong (e;g. the target server thinks you're following, but your instance thinks you're not yet), it's better to first sent an unfollow. This is the behaviour that Mastodon and most probably most other clients have. Therefore this flow is more tested and expected by other instances.
2021-12-12 18:09:21 +01:00
HJ a20f1794d0 Merge branch 'simplePolicy_reasons_for_instance_specific_policies' into 'develop'
Simple policy reasons for instance specific policies

See merge request pleroma/pleroma-fe!1263
2021-12-03 18:14:32 +00:00
Ilja b4cfda4a20 Simple policy reasons for instance specific policies 2021-12-03 18:14:32 +00:00
HJ ea0887a15e Merge branch 'fix/escape-display-name' into 'develop'
entity_normalizer: Escape name when parsing user

See merge request pleroma/pleroma-fe!1415
2021-11-16 17:45:14 +00:00
rinpatch d36b45ad43 entity_normalizer: Escape name when parsing user
In January 2020 Pleroma backend stopped escaping HTML in display names
and passed that responsibility on frontends, compliant with Mastodon's
version of Mastodon API [1]. Pleroma-FE was subsequently modified to
escape the display name [2], however only in the "name_html" field. This
was fine however, since that's what the code rendering display names used.

However, 2 months ago an MR [3] refactoring the way the frontend does emoji
and mention rendering was merged. One of the things it did was moving away
from doing emoji rendering in the entity normalizer and use the unescaped
'user.name' in the rendering code, resulting in HTML injection being
possible again.

This patch escapes 'user.name' as well, as far as I can tell there is no
actual use for an unescaped display name in frontend code, especially
when it comes from MastoAPI, where it is not supposed to be HTML.

[1]: https://git.pleroma.social/pleroma/pleroma-fe/-/merge_requests/1052
[2]: https://git.pleroma.social/pleroma/pleroma/-/merge_requests/2167
[3]: https://git.pleroma.social/pleroma/pleroma-fe/-/merge_requests/1392
2021-11-16 20:35:23 +03:00
HJ ef5bbc4e5f Merge branch 'themeApply' into 'develop'
Minor QOL improvement: Theme tab Apply and Reset buttons shouldn't require scrolling

See merge request pleroma/pleroma-fe!1397
2021-09-09 22:00:20 +00:00
HJ 370f1e55ad Merge branch 'develop' into 'themeApply'
# Conflicts:
#   CHANGELOG.md
2021-09-09 21:51:39 +00:00
HJ a8a82ad12f Merge branch 'showMobileNewPost' into 'develop'
New user option: Always show floating New Post button

See merge request pleroma/pleroma-fe!1395
2021-09-09 12:19:53 +00:00
HJ 1c53528433 Merge branch 'fix-favico-badge-chrome' into 'develop'
fix favico badge not working on chrome

See merge request pleroma/pleroma-fe!1391
2021-09-07 16:17:31 +00:00
HJ 8af1f08539 Merge branch 'better-still-emoji' into 'develop'
Status HTML parsing - better emoji and mentions rendering

Closes #935

See merge request pleroma/pleroma-fe!1392
2021-09-07 16:15:41 +00:00
Shpuld Shpludson 25a8b48bf2 Merge branch 'from/develop/tusooa/fix-mobile-shoutbox-display' into 'develop'
Fix mobile shoutbox display

See merge request pleroma/pleroma-fe!1404
2021-09-07 14:46:39 +00:00
HJ 59bab829a6 Merge branch 'weblate-pleroma-pleroma-fe' into 'develop'
Translations update from Weblate

See merge request pleroma/pleroma-fe!1412
2021-09-05 12:31:23 +00:00
Hồ Nhất Duy 13468f2a89 Translated using Weblate (Vietnamese)
Currently translated at 50.0% (358 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/vi/
2021-09-05 04:46:01 +00:00
@liimee 5bb471a68e Translated using Weblate (Indonesian)
Currently translated at 67.3% (482 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/id/
2021-09-05 04:45:45 +00:00
Kana ff5ed29ec1 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (716 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hans/
2021-09-05 04:45:43 +00:00
tarteka fa75a3a615 Translated using Weblate (Basque)
Currently translated at 80.7% (578 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/eu/
2021-09-05 04:45:43 +00:00
HJ 057e3dac85 Merge branch 'weblate-pleroma-pleroma-fe' into 'develop'
Translations update from Weblate

See merge request pleroma/pleroma-fe!1388
2021-09-02 16:58:11 +00:00
Hồ Nhất Duy 6e57170626 Added translation using Weblate (Vietnamese) 2021-09-02 14:47:32 +00:00
@liimee 98da3ad124 Translated using Weblate (Indonesian)
Currently translated at 60.6% (434 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/id/
2021-08-30 15:24:16 +00:00
@liimee 144cee6d34 Translated using Weblate (Indonesian)
Currently translated at 58.6% (420 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/id/
2021-08-30 15:24:16 +00:00
tarteka 0543c8d536 Translated using Weblate (Basque)
Currently translated at 80.4% (576 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/eu/
2021-08-30 15:24:16 +00:00
marcin mikołajczak 9319666f04 Translated using Weblate (Polish)
Currently translated at 98.8% (708 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/pl/
2021-08-30 15:24:16 +00:00
@liimee ca9652b30b Translated using Weblate (Indonesian)
Currently translated at 56.9% (408 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/id/
2021-08-30 15:24:16 +00:00
tarteka 21af736fe1 Translated using Weblate (Basque)
Currently translated at 79.8% (572 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/eu/
2021-08-30 15:24:16 +00:00
tarteka 78ba8be969 Translated using Weblate (Spanish)
Currently translated at 100.0% (716 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/es/
2021-08-30 15:24:16 +00:00
@liimee 29f229daad Translated using Weblate (Indonesian)
Currently translated at 50.1% (359 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/id/
2021-08-30 15:24:16 +00:00
marcin mikołajczak 5049ee575f Translated using Weblate (Polish)
Currently translated at 98.7% (707 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/pl/
2021-08-30 15:24:16 +00:00
tarteka 32ed71501a Translated using Weblate (Spanish)
Currently translated at 100.0% (716 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/es/
2021-08-30 15:24:16 +00:00
@liimee a7a736c7b8 Added translation using Weblate (Indonesian) 2021-08-30 15:24:16 +00:00
tarteka 5cbb71e588 Translated using Weblate (Spanish)
Currently translated at 100.0% (716 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/es/
2021-08-30 15:24:16 +00:00
M. Strange fa2e5deae2 Translated using Weblate (Catalan)
Currently translated at 97.4% (698 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ca/
2021-08-30 15:24:16 +00:00
titizen a3bfa63d05 Translated using Weblate (Catalan)
Currently translated at 95.3% (683 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ca/
2021-08-30 15:24:16 +00:00
M. Strange 1ef2bb93fe Translated using Weblate (Catalan)
Currently translated at 92.0% (659 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ca/
2021-08-30 15:24:16 +00:00
titizen c38ab7234d Translated using Weblate (Catalan)
Currently translated at 92.0% (659 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ca/
2021-08-30 15:24:16 +00:00
ZEN 791293c709 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (716 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/uk/
2021-08-30 15:24:16 +00:00
M. Strange 8574db1cf1 Translated using Weblate (Catalan)
Currently translated at 56.1% (402 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ca/
2021-08-30 15:24:15 +00:00
Snow 90d553f4be Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (716 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hant/
2021-08-30 15:24:15 +00:00
Haelwenn (lanodan) Monnier d3139a92b3 Translated using Weblate (French)
Currently translated at 100.0% (716 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/fr/
2021-08-30 15:24:15 +00:00
Ben Is bc08f998cf Translated using Weblate (Italian)
Currently translated at 100.0% (716 of 716 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-08-30 15:24:15 +00:00
Tirifto f72671a1aa Translated using Weblate (Esperanto)
Currently translated at 100.0% (715 of 715 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/eo/
2021-08-30 15:24:15 +00:00
Ben Is 738e7923e4 Translated using Weblate (Italian)
Currently translated at 100.0% (715 of 715 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-08-30 15:24:15 +00:00
retiolus b3f15fe3e1 Translated using Weblate (Catalan)
Currently translated at 44.4% (318 of 715 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ca/
2021-08-30 15:24:15 +00:00
ZEN 761f91f7ef Translated using Weblate (Ukrainian)
Currently translated at 100.0% (715 of 715 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/uk/
2021-08-30 15:24:15 +00:00
Issabella Deinschnitzel c509ed357a Translated using Weblate (German)
Currently translated at 100.0% (715 of 715 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/de/
2021-08-30 15:24:15 +00:00
Ben Is 18871684c7 Translated using Weblate (Italian)
Currently translated at 100.0% (715 of 715 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-08-30 15:24:15 +00:00
Kana 33e2bcce31 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (714 of 714 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hans/
2021-08-30 15:24:15 +00:00
Ben Is 4d529c13ba Translated using Weblate (Italian)
Currently translated at 100.0% (714 of 714 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-08-30 15:24:15 +00:00
Ben Is 0e53b2916e Translated using Weblate (Italian)
Currently translated at 100.0% (714 of 714 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-08-30 15:24:15 +00:00
Tirifto 04a49e4c42 Translated using Weblate (Esperanto)
Currently translated at 99.7% (709 of 711 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/eo/
2021-08-30 15:24:15 +00:00
ZEN f57f61ca53 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (711 of 711 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/uk/
2021-08-30 15:24:15 +00:00
Ben Is 4302db5975 Translated using Weblate (Italian)
Currently translated at 100.0% (711 of 711 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-08-30 15:24:15 +00:00
Shpuld Shpludson cdcefc2b73 Merge branch 'fix-ext-profile' into 'develop'
fix ext profile bug

See merge request pleroma/pleroma-fe!1409
2021-08-30 15:24:06 +00:00
Henry Jameson 4d73eaa6ce fix spacing before hashtags 2021-08-23 21:36:18 +03:00
Henry Jameson 39494439d3 very minimalist hashtaglink implementation, also you can middle-click
mentions now.
2021-08-23 20:57:21 +03:00
Henry Jameson c3576211cb fix tests 2021-08-18 21:17:51 +03:00
Henry Jameson cbb34e2b0e fix expanded mentions spacing 2021-08-18 20:58:26 +03:00
Henry Jameson e98a2af39e hopefully final fix for spacings 2021-08-18 20:54:04 +03:00
Henry Jameson dbdc5e050f fix ext profile bug 2021-08-16 01:41:52 +03:00
Henry Jameson 0087d33c75 fix "+X more" sticking 2021-08-15 18:41:13 +03:00
Henry Jameson 8cc1ad67df fix links sticking to mentionsline 2021-08-15 18:11:38 +03:00
Henry Jameson f16658adfc fix tests 2021-08-15 02:59:14 +03:00
Henry Jameson 68b4323181 prevent infinite update loops 2021-08-15 02:55:45 +03:00
Henry Jameson 7d67e8f1cc remove obsolete tests 2021-08-15 02:44:36 +03:00
Henry Jameson 530ac4442b removed useless code, review change, fixed bug with tall statuses 2021-08-15 02:41:53 +03:00
Henry Jameson 4465de5241 fixed mentions line again 2021-08-14 22:03:09 +03:00
Henry Jameson 97e86381c8 remove old emoji added, everything emoji-bearing uses RichContent now 2021-08-13 13:12:33 +03:00
Henry Jameson 4c974f5ca2 richcontent support in polls, user cards and user profiles 2021-08-13 13:06:42 +03:00
Henry Jameson 6c6df29ed3 support richcontent in polls 2021-08-13 12:19:57 +03:00
Henry Jameson add5921b8b fix tests, add performance test (skipped, doesn't assert anything),
tweak max mentions count
2021-08-12 19:37:04 +03:00
Henry Jameson 2182af4058 made the code responsible for showing unwritten mentions actually work 2021-08-12 03:09:28 +03:00
Henry Jameson 2cfff1b8b9 remove new options for style and separate line, now groups all chained
mentions on a mentionsline regardless of placement. fixes spacing
2021-08-12 02:56:40 +03:00
Shpuld Shpludson 51d3d8d255 Merge branch 'develop' into 'master'
Update MASTER for 2.4.0

See merge request pleroma/pleroma-fe!1406
2021-08-08 13:16:00 +00:00
Shpuld Shpuldson cc170aa3ec Update master with 2.4.0 2021-08-08 16:14:22 +03:00
Shpuld Shpludson 4686993334 Merge branch 'shpuld-develop-patch-10585' into 'develop'
Update CHANGELOG.md for 2.4.0

See merge request pleroma/pleroma-fe!1405
2021-08-08 12:47:25 +00:00
Shpuld Shpludson 435f80133a Update CHANGELOG.md for 2.4.0 2021-08-08 12:38:51 +00:00
Tusooa Zhu ef277ae4e2 Fix mobile shoutbox 2021-08-03 20:11:06 -04:00
eris f35e3d0f3f Fix merge conflict in CHANGELOG
# Conflicts:
#   CHANGELOG.md
2021-07-22 20:47:36 +00:00
eris 179af131ee Fix changelog merge conflict
# Conflicts:
#   CHANGELOG.md
2021-07-22 20:46:41 +00:00
Shpuld Shpludson 425919a0d2 Merge branch 'fix-themes-select' into 'develop'
Fix theme select not working

See merge request pleroma/pleroma-fe!1393
2021-07-19 18:33:19 +00:00
HJ ba961b784f Apply 1 suggestion(s) to 1 file(s) 2021-07-19 17:10:13 +00:00
Shpuld Shpludson 891611816c Merge branch 'editProfile' into 'develop'
Minor change: Add edit profile button onto self user card

See merge request pleroma/pleroma-fe!1398
2021-07-19 16:35:28 +00:00
Shpuld Shpludson 373b14e1e4 Merge branch 'fix-settings-anon' into 'develop'
Fix Boolean/Choice settings not working properly on initial launch

See merge request pleroma/pleroma-fe!1389
2021-07-19 16:11:11 +00:00
Henry Jameson a0eaac2216 fix tests 2021-06-22 21:09:29 +03:00
Henry Jameson a258182522 fix non-notifying mentions and original mention display 2021-06-22 20:16:26 +03:00
eris 6125dc885a Update for latest develop merges to CHANGELOG 2021-06-20 21:06:59 +00:00
HJ 19475ba356 Merge branch 'develop' into 'develop'
Bug fix: Fix follow request count position on mobile

See merge request pleroma/pleroma-fe!1400
2021-06-20 09:09:32 +00:00
Eris cd9dd352e3 Fix follow request count position on mobile 2021-06-20 06:27:32 +00:00
Henry Jameson c6831a3810 fix not escaping some stuff 2021-06-18 21:42:46 +03:00
Henry Jameson 8fe4355a6b fix rich images 2021-06-18 21:29:47 +03:00
Henry Jameson b68fb7738b Merge remote-tracking branch 'origin/develop' into better-still-emoji
* origin/develop:
  Use proper setting name
  Use cleaner instance config check for shoutbox setting
  Make locale language cleaner
  Don't shorten shoutbox to SB
  Fix lint error
  Update CHANGELOG.md
  New option: Hide shoutbox
2021-06-18 02:27:57 +03:00
Eris 85e2f8f78c Don't show profile edit button in sidebar 2021-06-17 20:57:23 +00:00
eris b2ebfc1fd6 Merge branch 'develop' into 'editProfile'
# Conflicts:
#   CHANGELOG.md
2021-06-17 19:35:09 +00:00
Eris e1361a1cae Add edit profile button 2021-06-17 19:29:58 +00:00
Henry Jameson 1717a3aaf2 fix chats again 2021-06-16 12:44:04 +03:00
Henry Jameson 25bf28f051 added tests just in case 2021-06-16 02:11:24 +03:00
Henry Jameson ad3a2fd4e5 fixed "invisible" spans inside links 2021-06-16 01:20:20 +03:00
eris 139a0d1562 Merge branch 'develop' into 'themeApply'
# Conflicts:
#   CHANGELOG.md
2021-06-15 21:50:39 +00:00
eris cab0095989 Merge branch 'develop' into 'showMobileNewPost'
# Conflicts:
#   CHANGELOG.md
#   src/App.js
2021-06-15 21:49:33 +00:00
HJ 338134acfb Merge branch 'hideShoutbox' into 'develop'
New user option: Hide floating shoutbox

See merge request pleroma/pleroma-fe!1396
2021-06-15 21:32:20 +00:00
Eris d7a53aec61 Use proper setting name 2021-06-15 18:09:00 +00:00
Henry Jameson 4aac0125e5 fixed bug with hashtags 2021-06-15 14:43:44 +03:00
Eris 7e3393b5a2 Use cleaner instance config check for shoutbox setting 2021-06-15 00:59:36 +00:00
Eris 5047663c51 Make locale language cleaner 2021-06-15 00:25:09 +00:00
Eris e67f295497 Update CHANGELOG.md 2021-06-14 23:32:18 +00:00
Eris 312a237ca4 Revert duplicate buttons and move existing buttons to bottom-right corner independent of scroll 2021-06-14 23:31:16 +00:00
Eris 4639e30cb8 Fix config naming for consistency 2021-06-14 20:41:34 +00:00
Eris cbccea0546 Don't shorten shoutbox to SB 2021-06-14 20:33:51 +00:00
Eris b88e6b8ab0 Update CHANGELOG.md 2021-06-14 20:11:57 +00:00
Eris 8fa0331771 Add apply and reset themes to top of theme tab 2021-06-14 20:09:28 +00:00
Eris 1668315bf8 Fix lint error 2021-06-14 20:02:13 +00:00
Eris 1fcccd7570 Update CHANGELOG.md 2021-06-14 19:43:47 +00:00
Eris 0c10145242 New option: Hide shoutbox 2021-06-14 19:42:56 +00:00
Eris 67c9d8bd55 revert gitignore file change 2021-06-14 18:49:37 +00:00
Eris adfe56a3a3 New option: Always show floating New Post button 2021-06-14 17:54:40 +00:00
Henry Jameson 63c22ad131 Fixed mergedConfig misbehaving on first boot 2021-06-14 10:58:32 +03:00
Henry Jameson 7309f8ce1a lint 2021-06-14 10:31:07 +03:00
Henry Jameson c21b1cf898 do the impossible, fix the unfixable 2021-06-14 10:30:08 +03:00
Henry Jameson 636dbdaba8 more fixes 2021-06-13 22:22:59 +03:00
Henry Jameson 1fdfc42159 fix mentions in chats 2021-06-13 21:43:45 +03:00
Henry Jameson 609dc5da0c fix chats messages 2021-06-13 21:42:25 +03:00
Henry Jameson bebafa1a2c refactored line converter, untied its logic from greentexting, better
handling of broken cases
2021-06-13 15:24:29 +03:00
HJ e825021ef1 Apply 1 suggestion(s) to 1 file(s) 2021-06-12 18:55:18 +00:00
Henry Jameson 9c70f3e4df fixed a bug + made a testcase out of it 2021-06-12 21:49:56 +03:00
Henry Jameson 2c60a9b638 fix next relply-row bleeding through popover 2021-06-12 20:51:36 +03:00
Henry Jameson 18fb7516cc lint 2021-06-12 20:44:14 +03:00
Henry Jameson 418f029789 review + fixes 2021-06-12 20:43:29 +03:00
Henry Jameson 90a188f2c3 cleanup 2021-06-12 19:54:34 +03:00
Henry Jameson cd44556750 restructure and tests
squash! restructure and tests
2021-06-12 19:54:30 +03:00
Henry Jameson ca6c7d5b10 fix tags gluing 2021-06-12 17:20:21 +03:00
Henry Jameson 24f3681ac1 fix color of reply row, fix overflow in status-popover 2021-06-12 17:11:49 +03:00
Henry Jameson 647e4476f9 fix long post fader 2021-06-12 16:25:37 +03:00
Henry Jameson c1bd36dc6f change how "first" line is determined. Allow one mention in the
beginning for hellthread style
2021-06-12 16:15:22 +03:00
Henry Jameson ffc501eb23 cleanup 2021-06-11 13:38:08 +03:00
Henry Jameson 9421501c1e lint & cleanup 2021-06-11 11:52:50 +03:00
Henry Jameson 5834790d0b fix #935 2021-06-11 11:50:05 +03:00
Henry Jameson f819227bed fixed console errors, improved user-selecting, added cyantexting 2021-06-11 11:49:32 +03:00
Henry Jameson 255f47fe56 fix infinite loop 2021-06-11 11:05:28 +03:00
Henry Jameson f883d2f75c better handling of hellthreads with mentions at bottom 2021-06-11 03:11:58 +03:00
Henry Jameson b84aeff6bf stylistic changes 2021-06-10 18:52:23 +03:00
Henry Jameson cc00af7a31 Hellthread(tm) Certified 2021-06-10 18:52:01 +03:00
Henry Jameson 0f73e96194 don't hide mentions for OPs 2021-06-10 15:11:57 +03:00
Henry Jameson 0263834faa mentions on same line as replies 2021-06-10 14:01:26 +03:00
Henry Jameson 6bff7cc6ef use icon instead of symbol for @ in mentions links 2021-06-10 13:29:59 +03:00
Henry Jameson 0260693f51 stylistic improvements for single-line mentions 2021-06-10 13:22:36 +03:00
Henry Jameson 394fd462dc proper cachin of headTailLinks, show mentions in notificaitons always 2021-06-10 13:01:00 +03:00
Henry Jameson c6c478f4cf moved mentions onto reply line, replies moved below post body 2021-06-10 12:29:58 +03:00
Henry Jameson aec867b300 Moved greentext to RichContent, improved how first mentions are
restored, now shows mentions not uh, mention in post body
2021-06-10 12:29:58 +03:00
Henry Jameson 566964992a fix long posts having weird gradient 2021-06-08 19:37:18 +03:00
Henry Jameson 5c655b6675 lint 2021-06-08 17:19:38 +03:00
Henry Jameson 8c8237418c fix repeats having wrong mentions 2021-06-08 17:14:22 +03:00
Henry Jameson 963f1679e0 fix console errors 2021-06-08 17:14:22 +03:00
Henry Jameson a3b8e7ad99 missing localization 2021-06-08 16:37:13 +03:00
Henry Jameson 7ae85c8318 change defaults 2021-06-08 14:51:42 +03:00
Henry Jameson 0ae3985a52 bump limit to a saner one 2021-06-08 14:36:41 +03:00
Henry Jameson 2f383c2c01 moved mentions into a separate component - MentionLine, added collapsing
of mentions when there's too many of 'em
2021-06-08 14:34:47 +03:00
Henry Jameson 73127f0e25 fix empty spaces again 2021-06-08 13:42:16 +03:00
Henry Jameson 9ea370033a configurable mentions placement 2021-06-08 12:58:28 +03:00
Henry Jameson 3abd357694 moving mentions into separate row 2021-06-08 11:38:44 +03:00
Henry Jameson 0583a6b863 moved transparent button styles into button itself 2021-06-08 10:14:49 +03:00
Henry Jameson 6bc9886db4 tweaking the spacings 2021-06-08 01:25:03 +03:00
Henry Jameson ccdf892483 remove weird vertical align 2021-06-08 01:21:45 +03:00
Henry Jameson 38d9ea8b17 lint 2021-06-08 00:09:16 +03:00
Henry Jameson 5740a79dbd faint @ 2021-06-08 00:06:26 +03:00
Henry Jameson e6d5ddcbb6 better modifier, no background for unhighlighted mentions 2021-06-08 00:03:59 +03:00
Henry Jameson 59d046b163 fix theme selection not working 2021-06-07 23:48:46 +03:00
Henry Jameson c3e122ff6f smaller mentions 2021-06-07 23:48:01 +03:00
Henry Jameson 7d6fc044fb new mentions look 2021-06-07 23:42:04 +03:00
Henry Jameson 6199788f28 fix tall emojis being cropped 2021-06-07 20:44:32 +03:00
Henry Jameson 8045d1866e localization 2021-06-07 20:25:31 +03:00
Henry Jameson 6090327236 moved some post styles into status body since they inferfere with usernames 2021-06-07 20:02:09 +03:00
Henry Jameson 5e83672274 fixed some strange error 2021-06-07 20:01:57 +03:00
Henry Jameson aa38223e87 lint 2021-06-07 19:51:04 +03:00
Henry Jameson 8e9f5d7580 renamed StatusText to StatusBody for clarity, fixed chats 2021-06-07 19:50:38 +03:00
Henry Jameson 50aa379038 new component - StatusText, to separate post's text from its attachments 2021-06-07 18:41:55 +03:00
Henry Jameson 04fa1f0b2d some docs, added richcontent to usernames in status, updated stillImage
to allow scale of "gif" label
2021-06-07 18:41:47 +03:00
Henry Jameson aec05686d0 lint, fix warnings 2021-06-07 18:41:47 +03:00
Henry Jameson b0ae32e309 made getAttrs correctly handle both ' and " 2021-06-07 18:41:47 +03:00
Henry Jameson 22c8f71945 mention link 2021-06-07 18:41:47 +03:00
Henry Jameson 1923ed84d4 more tests 2021-06-07 18:41:47 +03:00
Henry Jameson a2459c2187 move styles to richcontent 2021-06-07 18:41:47 +03:00
Henry Jameson be79643bcf fix emoji processor not leaving string as-is if no emoji are found 2021-06-07 18:41:47 +03:00
Henry Jameson 35dedf8416 lint 2021-06-07 18:41:47 +03:00
Henry Jameson 5970ddf9ac fix escaped apostrophes 2021-06-07 18:41:47 +03:00
Henry Jameson 20ce646852 [WIP] MUCH better approach to replacing emojis with still versions 2021-06-07 18:41:47 +03:00
HJ 2725a0c639 Merge branch 'chore/rename-chat' into 'develop'
Rename legacy PleromaFE Chat functionality to "Shout"

See merge request pleroma/pleroma-fe!1207
2021-06-03 20:16:48 +00:00
Mark Felder bd98ecb3f0 Remove unused shoutbox channel state from side drawer 2021-06-03 15:07:02 -05:00
Henry Jameson 2a2483f4c9 handle multiple favicons (different sizes) 2021-06-02 12:47:54 +03:00
Henry Jameson 008e711e11 fix favico badge not working on chrome 2021-06-02 12:15:31 +03:00
Mark Felder 21477d07e9 This setting didn't actually do anything 2021-06-01 16:51:47 -05:00
Mark Felder ed824d964e Use old value to discover if Shoutbox is available until we ship a new release that's declaring the feature as "shout" 2021-06-01 16:48:40 -05:00
Mark Felder e0cde9a29b Keep channel name the same for backwards compatibility 2021-06-01 14:31:58 -05:00
Mark Felder 0604b1d5b7 Rename legacy PleromaFE Chat functionality to "Shout" 2021-06-01 12:51:20 -05:00
Henry Jameson 32d1a0e181 better approach 2021-05-31 14:23:57 +03:00
HJ 7bd18cda64 Merge branch 'vue3compat-emoji-input' into 'develop'
Refactor EmojiInput for better vue3 compatibility

See merge request pleroma/pleroma-fe!1382
2021-05-31 11:17:42 +00:00
Henry Jameson e95412a03c fix BooleanSetting and ChoiceSetting not working properly on initial
launch as anon visitor (would show all as changed, empty selects)
2021-05-31 14:16:37 +03:00
HJ 0ca0e642a4 Merge branch 'v-slot-upgrade' into 'develop'
Change old slot syntax (removed in vue3) to new one

See merge request pleroma/pleroma-fe!1379
2021-05-31 11:15:44 +00:00
HJ 4e96af0442 Merge branch 'better-selects' into 'develop'
Better <select> components

See merge request pleroma/pleroma-fe!1373
2021-05-31 11:08:56 +00:00
Henry Jameson 80220c1b07 fix warnings 2021-05-31 14:08:12 +03:00
Henry Jameson c039656460 fix warnings 2021-05-31 14:02:36 +03:00
HJ dc611dffdb Merge branch 'flash-support' into 'develop'
Flash support

See merge request pleroma/pleroma-fe!1380
2021-05-31 11:00:53 +00:00
Henry Jameson 159bbed2f9 oops 2021-05-31 13:59:44 +03:00
Henry Jameson 245addb530 remove "leak ur cookiz" 2021-05-31 13:55:28 +03:00
HJ 0741d1d93d Merge branch 'weblate-pleroma-pleroma-fe' into 'develop'
Translations update from Weblate

See merge request pleroma/pleroma-fe!1378
2021-05-26 22:23:56 +00:00
HJ 477e22aa9c Merge branch 'feat/sidebarRight' into 'develop'
Implement right sidebar option as user option

See merge request pleroma/pleroma-fe!1387
2021-05-26 22:22:55 +00:00
eris 7341b8a551 Implement right sidebar option as user option 2021-05-26 22:22:55 +00:00
Issabella Deinschnitzel 711bf0910a Translated using Weblate (German)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/de/
2021-05-22 16:36:51 +00:00
Ben Is 330665dacb Translated using Weblate (Italian)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-05-19 13:41:25 +00:00
Issabella Deinschnitzel e338f6be75 Translated using Weblate (German)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/de/
2021-05-16 20:19:26 +00:00
Snow eda817cc18 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hant/
2021-05-12 12:09:34 +00:00
Issabella Deinschnitzel 1e0479b171 Translated using Weblate (German)
Currently translated at 95.9% (681 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/de/
2021-05-12 12:09:33 +00:00
Issabella Deinschnitzel 64aba422d5 Translated using Weblate (German)
Currently translated at 88.4% (628 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/de/
2021-05-11 15:53:02 +00:00
Anonymous 98da8fd441 Translated using Weblate (German)
Currently translated at 88.4% (628 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/de/
2021-05-11 15:53:00 +00:00
Ryo Ueno b50a9a1d56 Translated using Weblate (Korean)
Currently translated at 62.6% (445 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ko/
2021-05-06 16:41:19 +00:00
grillchen fdd4be3dcb Translated using Weblate (German)
Currently translated at 72.8% (517 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/de/
2021-05-02 14:03:24 +00:00
Anonymous 407bdbf996 Translated using Weblate (German)
Currently translated at 67.7% (481 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/de/
2021-04-30 18:43:32 +00:00
grillchen cec13609cd Translated using Weblate (German)
Currently translated at 67.7% (481 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/de/
2021-04-30 18:43:31 +00:00
tarteka e55644f153 Translated using Weblate (Spanish)
Currently translated at 99.5% (707 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/es/
2021-04-30 00:26:51 +00:00
Anonymous 98d12beb9e Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-28 16:17:43 +00:00
Fristi d7607792fe Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-28 16:17:43 +00:00
grillchen f28f632e86 Translated using Weblate (German)
Currently translated at 63.6% (452 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/de/
2021-04-28 16:17:41 +00:00
Anonymous 62ba237217 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:44:49 +00:00
Fristi e053ac9865 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:44:48 +00:00
Anonymous e8449166e1 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:38:56 +00:00
Fristi fd3b806c24 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:38:55 +00:00
Anonymous 39b6214447 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:38:12 +00:00
Fristi f8fde93c51 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:38:11 +00:00
Anonymous a6f66cfa2a Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:37:50 +00:00
Fristi acfd70bd3e Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:37:49 +00:00
Anonymous 303cf39142 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:37:27 +00:00
Fristi 31e342a005 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:37:26 +00:00
Anonymous 61b60f8aa3 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:37:04 +00:00
Fristi 98735bf340 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:37:03 +00:00
Anonymous 4cebc94324 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:35:36 +00:00
Fristi be09a42253 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:35:35 +00:00
Anonymous 3a0d4fdc24 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:35:01 +00:00
Fristi 6d40c4f9be Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:35:00 +00:00
Anonymous 5e82b7e316 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:06:26 +00:00
Fristi dc81367260 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:06:25 +00:00
Anonymous e262103e7d Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:02:51 +00:00
Fristi 2d8c325926 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 18:02:50 +00:00
Anonymous 78fbee36aa Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 17:58:13 +00:00
Fristi 099b5a7d38 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 17:58:12 +00:00
Anonymous 55fa353469 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 17:57:51 +00:00
Fristi 70cef8d9b5 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 17:57:50 +00:00
Anonymous e958c8e943 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 17:42:55 +00:00
Fristi a0453f7af8 Translated using Weblate (Dutch)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 17:42:54 +00:00
Anonymous 225f8c44d6 Translated using Weblate (Dutch)
Currently translated at 88.5% (629 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 16:47:24 +00:00
Fristi 8830a1652c Translated using Weblate (Dutch)
Currently translated at 88.5% (629 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 16:47:23 +00:00
Anonymous 3f68af086a Translated using Weblate (Dutch)
Currently translated at 88.1% (626 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 16:45:47 +00:00
Fristi b780f76b37 Translated using Weblate (Dutch)
Currently translated at 88.1% (626 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 16:45:46 +00:00
Anonymous b406ebdc39 Translated using Weblate (Dutch)
Currently translated at 87.8% (624 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 15:10:24 +00:00
Fristi 323cc8271f Translated using Weblate (Dutch)
Currently translated at 87.8% (624 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 15:10:23 +00:00
Anonymous 0578467ecf Translated using Weblate (Dutch)
Currently translated at 87.0% (618 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 10:28:20 +00:00
Fristi 35438d93f0 Translated using Weblate (Dutch)
Currently translated at 87.0% (618 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-27 10:28:12 +00:00
Anonymous 110a37f68f Translated using Weblate (Dutch)
Currently translated at 86.3% (613 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-25 13:55:30 +00:00
Fristi 4d54ae91d7 Translated using Weblate (Dutch)
Currently translated at 86.3% (613 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-25 13:55:30 +00:00
Anonymous 62679e24ab Translated using Weblate (Dutch)
Currently translated at 85.3% (606 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-25 13:46:41 +00:00
Fristi c1da12e2cd Translated using Weblate (Dutch)
Currently translated at 85.3% (606 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-25 13:46:40 +00:00
Fristi 5ef0184469 Translated using Weblate (Dutch)
Currently translated at 81.6% (580 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-25 13:37:14 +00:00
Anonymous b65ee94f93 Translated using Weblate (Dutch)
Currently translated at 81.6% (580 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nl/
2021-04-25 13:37:13 +00:00
ZEN e00c3ccf36 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/uk/
2021-04-22 13:49:34 +00:00
ZEN b486788ed9 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/uk/
2021-04-21 05:49:24 +00:00
Ryo Ueno 7acad87806 Translated using Weblate (Japanese)
Currently translated at 99.2% (705 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ja_PEDANTIC/
2021-04-21 05:49:24 +00:00
Ben Is 2d10084939 Translated using Weblate (Italian)
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-04-21 05:49:24 +00:00
Snow 7a46e81edf Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hant/
2021-04-21 05:49:24 +00:00
Anonymous 0775970476 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hans/
2021-04-21 05:49:24 +00:00
Kana 3f4487b5b8 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (710 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hans/
2021-04-21 05:49:24 +00:00
Snow 2435d93d2d Translated using Weblate (Chinese (Traditional))
Currently translated at 99.5% (707 of 710 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hant/
2021-04-21 05:49:24 +00:00
Ben Is 29faa6f124 Translated using Weblate (Italian)
Currently translated at 100.0% (702 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-04-21 05:49:24 +00:00
Snow b97dfec5f6 Translated using Weblate (Chinese (Traditional))
Currently translated at 99.4% (698 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hant/
2021-04-21 05:49:24 +00:00
ZEN 43b4223f16 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (702 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/uk/
2021-04-21 05:49:24 +00:00
tarteka 86a851849a Translated using Weblate (Spanish)
Currently translated at 100.0% (702 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/es/
2021-04-21 05:49:24 +00:00
Shpuld Shpludson 3dca3639fd Merge branch 'mp/normaliser-safety' into 'develop'
entity_normalizer: safely check screen_name

See merge request pleroma/pleroma-fe!1383
2021-04-21 05:49:15 +00:00
Matilde Park 06d0254cc5 entity_normalizer: safely check screen_name
Prevents a crash on undefined screen name cases.
2021-04-21 01:40:25 -04:00
Henry Jameson 40ac9ef499 backport vue3 changes related to emoji-input 2021-04-18 17:03:31 +03:00
Henry Jameson 09ef284af7 better label, better error handling 2021-04-13 00:08:17 +03:00
Henry Jameson 87903fbf6d do not load ruffle multiple times! 2021-04-12 01:15:59 +03:00
Henry Jameson 6b250762f0 translate a variable name to American English from Australian English 2021-04-12 00:52:16 +03:00
Henry Jameson f0641d05df linting 2021-04-12 00:07:28 +03:00
Henry Jameson 5fdc4a1904 whooops dropped my monstercondo 2021-04-12 00:03:17 +03:00
Henry Jameson adafae977a Play-on-click, layout improvements. 2021-04-12 00:00:23 +03:00
Henry Jameson 2f549774ab No longer need to put ruffle stuff in source tree. Made ruffle not use
polyfills also.
2021-04-11 23:03:03 +03:00
Henry Jameson d695dcaff9 experimental flash support through ruffle 2021-04-09 19:14:05 +03:00
Henry Jameson 61dcdbf992 migrate to v-slot 2021-04-07 22:42:34 +03:00
Henry Jameson 1afda1ac6d lost file 2021-04-07 20:53:58 +03:00
Henry Jameson 0c77a3e1d6 remove extra chevron post-merge 2021-04-07 20:47:59 +03:00
Henry Jameson 4e56e64034 Merge remote-tracking branch 'origin/develop' into better-selects
* origin/develop: (76 commits)
  Translated using Weblate (Italian)
  Translated using Weblate (Basque)
  Translated using Weblate (Spanish)
  Translated using Weblate (Chinese (Simplified))
  Translated using Weblate (Italian)
  Translated using Weblate (Chinese (Traditional))
  Translated using Weblate (Russian)
  Translated using Weblate (Italian)
  Translated using Weblate (French)
  Translated using Weblate (Russian)
  Translated using Weblate (Italian)
  Translated using Weblate (French)
  Translated using Weblate (Basque)
  Translated using Weblate (Spanish)
  Translated using Weblate (Chinese (Simplified))
  Translated using Weblate (Japanese)
  Translated using Weblate (Italian)
  Translated using Weblate (Esperanto)
  Translated using Weblate (Chinese (Traditional))
  Translated using Weblate (Norwegian Bokmål)
  ...
2021-04-07 20:45:57 +03:00
HJ 8b96ea9377 Merge branch 'settings-import-export' into 'develop'
Settings backup/restore + small fixes

See merge request pleroma/pleroma-fe!1372
2021-04-07 17:40:07 +00:00
HJ 4e3c4ec1db Merge branch 'weblate-pleroma-pleroma-fe' into 'develop'
Translations update from Weblate

See merge request pleroma/pleroma-fe!1365
2021-03-25 11:17:04 +00:00
Ben Is bb7d89cd8c Translated using Weblate (Italian)
Currently translated at 100.0% (702 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-03-22 18:00:04 +00:00
tarteka 16beb3cbda Translated using Weblate (Basque)
Currently translated at 79.2% (556 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/eu/
2021-03-17 13:26:02 +00:00
tarteka 9701a28a34 Translated using Weblate (Spanish)
Currently translated at 100.0% (702 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/es/
2021-03-17 13:26:02 +00:00
Kana 5be18d177d Translated using Weblate (Chinese (Simplified))
Currently translated at 99.8% (701 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hans/
2021-03-17 13:26:02 +00:00
Ben Is 5d9f1fa76f Translated using Weblate (Italian)
Currently translated at 100.0% (702 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-03-17 13:26:02 +00:00
Snow d3ae0b3b97 Translated using Weblate (Chinese (Traditional))
Currently translated at 97.5% (685 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hant/
2021-03-17 13:26:02 +00:00
rinpatch e11e23e6f9 Translated using Weblate (Russian)
Currently translated at 88.6% (622 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:02 +00:00
Ben Is dc37f07fe2 Translated using Weblate (Italian)
Currently translated at 100.0% (702 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-03-17 13:26:02 +00:00
Haelwenn (lanodan) Monnier 2367e7ce8f Translated using Weblate (French)
Currently translated at 100.0% (702 of 702 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/fr/
2021-03-17 13:26:02 +00:00
rinpatch 5872e3dd54 Translated using Weblate (Russian)
Currently translated at 88.5% (619 of 699 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:02 +00:00
Ben Is 2392307290 Translated using Weblate (Italian)
Currently translated at 100.0% (697 of 697 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-03-17 13:26:02 +00:00
Haelwenn (lanodan) Monnier e199f26632 Translated using Weblate (French)
Currently translated at 100.0% (697 of 697 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/fr/
2021-03-17 13:26:02 +00:00
tarteka d716026f54 Translated using Weblate (Basque)
Currently translated at 79.7% (555 of 696 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/eu/
2021-03-17 13:26:02 +00:00
tarteka 9801906ea1 Translated using Weblate (Spanish)
Currently translated at 100.0% (696 of 696 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/es/
2021-03-17 13:26:02 +00:00
Kana cf35a9697e Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (696 of 696 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hans/
2021-03-17 13:26:02 +00:00
Ryo Ueno c97ad72cf0 Translated using Weblate (Japanese)
Currently translated at 100.0% (696 of 696 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ja_PEDANTIC/
2021-03-17 13:26:02 +00:00
Ben Is 41034141d8 Translated using Weblate (Italian)
Currently translated at 100.0% (696 of 696 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-03-17 13:26:01 +00:00
Tirifto 0a4efeb843 Translated using Weblate (Esperanto)
Currently translated at 100.0% (696 of 696 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/eo/
2021-03-17 13:26:01 +00:00
Snow fb1e57b6b6 Translated using Weblate (Chinese (Traditional))
Currently translated at 99.4% (692 of 696 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hant/
2021-03-17 13:26:01 +00:00
fiftyffs ecac5bb015 Translated using Weblate (Norwegian Bokmål)
Currently translated at 69.8% (486 of 696 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nb_NO/
2021-03-17 13:26:01 +00:00
Ben Is ba8a2f4a20 Translated using Weblate (Italian)
Currently translated at 100.0% (696 of 696 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-03-17 13:26:01 +00:00
Haelwenn (lanodan) Monnier 7fa7809c50 Translated using Weblate (French)
Currently translated at 100.0% (696 of 696 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/fr/
2021-03-17 13:26:01 +00:00
rinpatch 615925e53d Translated using Weblate (Russian)
Currently translated at 88.6% (617 of 696 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
rinpatch bb1bcfd084 Translated using Weblate (Russian)
Currently translated at 88.0% (609 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
Ben Is f8e2fde99b Translated using Weblate (Italian)
Currently translated at 100.0% (692 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-03-17 13:26:01 +00:00
Haelwenn (lanodan) Monnier 35d2a809d2 Translated using Weblate (French)
Currently translated at 97.1% (672 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/fr/
2021-03-17 13:26:01 +00:00
Kana fa6aba1dbd Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (692 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/zh_Hans/
2021-03-17 13:26:01 +00:00
Dmitriy Nelovchenko 2e6a7c9fb8 Translated using Weblate (Russian)
Currently translated at 87.8% (608 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
rinpatch b0d450075d Translated using Weblate (Russian)
Currently translated at 87.8% (608 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
Tirifto 6829c92f63 Translated using Weblate (Esperanto)
Currently translated at 99.5% (689 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/eo/
2021-03-17 13:26:01 +00:00
Dmitriy Nelovchenko 47507b72dc Translated using Weblate (Russian)
Currently translated at 86.1% (596 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
rinpatch 37944a19c3 Translated using Weblate (Russian)
Currently translated at 86.1% (596 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
Dmitriy Nelovchenko 65e510c3f2 Translated using Weblate (Russian)
Currently translated at 85.2% (590 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
rinpatch f28d71d769 Translated using Weblate (Russian)
Currently translated at 85.2% (590 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
Dmitriy Nelovchenko 73b053db5c Translated using Weblate (Russian)
Currently translated at 84.9% (588 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
rinpatch a450772039 Translated using Weblate (Russian)
Currently translated at 84.9% (588 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
Dmitriy Nelovchenko fe1d90ebc3 Translated using Weblate (Russian)
Currently translated at 84.8% (587 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
rinpatch e9ead1bfdd Translated using Weblate (Russian)
Currently translated at 84.8% (587 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
Anonymous 7ef1db1556 Translated using Weblate (Russian)
Currently translated at 84.8% (587 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
rinpatch 3739c58855 Translated using Weblate (Russian)
Currently translated at 84.8% (587 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
Dmitriy Nelovchenko 3a07fe2572 Translated using Weblate (Russian)
Currently translated at 84.8% (587 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
rinpatch 8a9913c5f6 Translated using Weblate (Russian)
Currently translated at 84.8% (587 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
Dmitriy Nelovchenko 0a0bb6078b Translated using Weblate (Russian)
Currently translated at 84.8% (587 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
rinpatch 08a44ee4a1 Translated using Weblate (Russian)
Currently translated at 84.8% (587 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
Dmitriy Nelovchenko 822d73c221 Translated using Weblate (Russian)
Currently translated at 84.8% (587 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
rinpatch deac610df6 Translated using Weblate (Russian)
Currently translated at 84.8% (587 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ru/
2021-03-17 13:26:01 +00:00
Ryo Ueno a7d64d038a Translated using Weblate (Korean)
Currently translated at 66.7% (462 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ko/
2021-03-17 13:26:01 +00:00
Ryo Ueno f70921b984 Translated using Weblate (Japanese)
Currently translated at 100.0% (692 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ja_PEDANTIC/
2021-03-17 13:26:01 +00:00
Ben Is d839c1ac89 Translated using Weblate (Italian)
Currently translated at 100.0% (692 of 692 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/it/
2021-03-17 13:26:01 +00:00
Shpuld Shpludson aacd909846 Merge branch 'feat/moderation-tools-chevron' into 'develop'
Add a chevron to moderation tools button to indicate it opens a menu

Closes #1069

See merge request pleroma/pleroma-fe!1377
2021-03-17 13:25:43 +00:00
Shpuld Shpludson d57ee274de Merge branch 'feat/notification-quick-filters' into 'develop'
Add quick filters for notifications

See merge request pleroma/pleroma-fe!1364
2021-03-17 08:17:23 +00:00
Shpuld Shpuldson 8163c7b55b v-slot 2021-03-16 08:35:29 +02:00
rinpatch 4c36ac12b6 Add a chevron to moderation tools button to indicate it opens a menu
Closes #1069
2021-03-15 17:49:52 +03:00
Shpuld Shpludson d262f208dc Merge branch 'feat/do-not-capitalize-every-word' into 'develop'
Do not capitalize every word in random strings

See merge request pleroma/pleroma-fe!1376
2021-03-15 12:33:44 +00:00
rinpatch feb40ec5ff Do not capitalize every word in random strings
Capitalization like that is only ever used in article/book titles, I
have not seen another website use it in interface elements.
2021-03-15 13:49:03 +03:00
Shpuld Shpludson 5ce298ead4 Merge branch 'feat/replace-generic-submit' into 'develop'
Use more specific button titles instead of general.submit

See merge request pleroma/pleroma-fe!1375
2021-03-15 10:38:04 +00:00
rinpatch 47719571e4 Use more specific button titles instead of general.submit
- "Post" for post submission (we already had the button title be "Posting"
when the post was being sent, so there was a weird inconsistency)
- "Register" for registration submission
- "Save changes" for usages in settings
2021-03-15 13:28:33 +03:00
Shpuld Shpludson a00212a3bb Merge branch 'websocket-fixes' into 'develop'
Various websocket fixes

See merge request pleroma/pleroma-fe!1326
2021-03-15 09:45:38 +00:00
Shpuld Shpuldson c682c1730f fix changelog 2021-03-15 11:05:00 +02:00
Shpuld Shpuldson 19fc7dda9e merge conflict, use v-slot:trigger, fix popover svg dimensions bug 2021-03-15 11:02:16 +02:00
Shpuld Shpludson 184364c7e0 Merge branch 'feat/timeline-menu-in-navpanel' into 'develop'
Add timeline menu toggle to nav panel

See merge request pleroma/pleroma-fe!1352
2021-03-15 07:03:22 +00:00
Henry Jameson 2da37f15ab Cleanup boolean/choice setting 2021-03-11 17:04:31 +02:00
Henry Jameson 8e88d8110b fix for filtering tab 2021-03-11 17:00:58 +02:00
Henry Jameson 1f0ac68fcd implement ChoiceSetting for settings modal similar to BooleanSetting 2021-03-11 16:55:14 +02:00
Henry Jameson 3870a30aea cleanup, fixes 2021-03-11 16:54:03 +02:00
Henry Jameson 5d3bf43fdc ghost styles for poll form 2021-03-11 16:54:03 +02:00
Henry Jameson c6d4c20982 Made Select component to make using styled selects easier 2021-03-11 16:11:44 +02:00
Henry Jameson 5c064ccf55 fix some css problems + tiny bit cleaning up 2021-03-11 15:14:30 +02:00
Shpuld Shpludson 0475e1c61c Update CHANGELOG.md 2021-03-09 09:45:28 +00:00
Shpuld Shpludson 088683538d Update CHANGELOG.md 2021-03-09 09:45:14 +00:00
Shpuld Shpludson badb2196a2 Merge branch 'develop' into 'feat/notification-quick-filters'
# Conflicts:
#   CHANGELOG.md
2021-03-09 09:43:01 +00:00
Henry Jameson a8967d85bd streamlined WS flow, reduced spam amount related to WS reconnections 2021-03-09 02:38:10 +02:00
Henry Jameson 90afcd3420 WIP some work on making errors less spammy 2021-03-08 22:24:39 +02:00
Henry Jameson 2e7bd99444 Merge remote-tracking branch 'origin/develop' into websocket-fixes
* origin/develop: (119 commits)
  Apply 1 suggestion(s) to 1 file(s)
  Make it possible to localize user highlight options
  remove shoutbox test hacks
  fix shoutbox header, use custom scroll-to-bottom system, remove vue-chat-scroll, temporarily add chat test hack
  update changelog with 2.3.0
  change icons around
  Translated using Weblate (Japanese)
  Update timeline_quick_settings.js
  add screen_name_ui to tests
  separate screen_name and screen_name_ui with decoded punycode
  Update CHANGELOG.md
  add basic validation for statusless status notifications
  changelog mention
  fix chat unread badge
  update shelljs to get rid of warnings on build
  save a few characters
  focus input in emoji picker and react picker
  fix vue warnings
  add only to wording
  basic loggedin check for reply filtering
  ...
2021-03-08 22:01:28 +02:00
Henry Jameson 3d95ea6acb cleanup + fix 2021-03-08 21:56:20 +02:00
Henry Jameson fada49768d extra protection to not write what we don't know 2021-03-08 21:14:03 +02:00
Henry Jameson 914b4eb593 lint 2021-03-08 21:03:55 +02:00
Henry Jameson 395e12cbc6 better error/warnings 2021-03-08 21:00:43 +02:00
Henry Jameson dda95543e8 implemented import/export for themes 2021-03-08 19:53:30 +02:00
Henry Jameson bd5b62b107 changed importexport into a service instead of component for simplicity 2021-03-08 19:42:24 +02:00
Henry Jameson 4baa397ed0 fixed another problem with p's broken theme causing theme editor to
become unusable
2021-03-08 19:19:16 +02:00
Henry Jameson 8a590f9269 Cleaned up panel-footer. No longer uses header styles since those look
and work ugly.
2021-03-08 19:18:43 +02:00
Shpuld Shpludson 6281241b92 Merge branch 'feat/user-highlight-localizable' into 'develop'
Make it possible to localize user highlight options

See merge request pleroma/pleroma-fe!1369
2021-03-04 20:02:57 +00:00
rinpatch c14c144cc8 Apply 1 suggestion(s) to 1 file(s) 2021-03-04 19:46:03 +00:00
rinpatch b4f5df9ce5 Make it possible to localize user highlight options 2021-03-04 22:24:17 +03:00
Shpuld Shpludson fb183adc74 Merge branch 'fix/shoutbox-fixes' into 'develop'
Remove vue-chat-scroll, fix up shoutbox header

See merge request pleroma/pleroma-fe!1368
2021-03-03 15:07:10 +00:00
Shpuld Shpuldson becacf0643 remove shoutbox test hacks 2021-03-03 16:47:59 +02:00
Shpuld Shpuldson 0673511fc2 fix shoutbox header, use custom scroll-to-bottom system, remove vue-chat-scroll, temporarily add chat test hack 2021-03-03 16:46:53 +02:00
Shpuld Shpludson 30057a4944 Merge branch 'chore/update-changelog' into 'develop'
update changelog with 2.3.0

See merge request pleroma/pleroma-fe!1367
2021-03-02 08:03:59 +00:00
Shpuld Shpuldson d1ab424ebc update changelog with 2.3.0 2021-03-02 09:53:17 +02:00
Shpuld Shpuldson ae159f6ad8 ui never refers to them as likes 2021-03-01 16:30:10 +02:00
Shpuld Shpuldson 11a036d6d6 changelog 2021-03-01 16:27:24 +02:00
Shpuld Shpuldson f6af4c43f6 add quick filters for notifications2 2021-03-01 16:21:35 +02:00
Shpuld Shpludson 6d7b5b157b Merge branch 'feat/timeline-quick-settings' into 'develop'
close #1050 - add a quick settings menu to timeline header

Closes #1050

See merge request pleroma/pleroma-fe!1355
2021-03-01 12:12:12 +00:00
Shpuld Shpuldson fc5483f764 change icons around 2021-03-01 10:14:17 +02:00
HJ a90910be8f Merge branch 'weblate-pleroma-pleroma-fe' into 'develop'
Translations update from Weblate

See merge request pleroma/pleroma-fe!1363
2021-03-01 00:10:45 +00:00
Ryo Ueno 846e58c3d2 Translated using Weblate (Japanese)
Currently translated at 100.0% (686 of 686 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ja_PEDANTIC/
2021-03-01 00:00:58 +00:00
Shpuld Shpludson 91f93d4a55 Merge branch 'develop' into 'feat/timeline-quick-settings'
# Conflicts:
#   CHANGELOG.md
2021-02-28 15:37:39 +00:00
Shpuld Shpludson 670abd633f Update timeline_quick_settings.js 2021-02-28 15:36:51 +00:00
Shpuld Shpludson b4782ad159 Merge branch 'feat/sensitive-by-default' into 'develop'
close #1054 add sensitive by default option

Closes #1054

See merge request pleroma/pleroma-fe!1354
2021-02-27 18:31:13 +00:00
Shpuld Shpludson 92a9ce67c5 Update CHANGELOG.md 2021-02-27 18:23:11 +00:00
Shpuld Shpludson aa5cb3d1d2 Merge branch 'fix/punycode-buggy' into 'develop'
Fix punycode handling to be less stupid

Closes #1064

See merge request pleroma/pleroma-fe!1361
2021-02-27 18:12:52 +00:00
Shpuld Shpludson 237f272d15 Merge branch 'develop' into 'fix/punycode-buggy'
# Conflicts:
#   CHANGELOG.md
2021-02-27 18:03:49 +00:00
Shpuld Shpludson a83fdbbd59 Merge branch 'fix/dont-crash-on-invalid-notificaiton' into 'develop'
close #1043 - add basic validation for statusless status notifications

Closes #1043

See merge request pleroma/pleroma-fe!1360
2021-02-27 16:57:46 +00:00
Shpuld Shpludson 7c37f495f6 Update CHANGELOG.md 2021-02-26 12:36:58 +00:00
Shpuld Shpuldson cd2f5ced31 add basic validation for statusless status notifications 2021-02-26 14:27:25 +02:00
Shpuld Shpuldson 096747a5dc add only to wording 2021-02-25 11:12:51 +02:00
Shpuld Shpuldson 93785634a7 basic loggedin check for reply filtering 2021-02-25 11:01:11 +02:00
Shpuld Shpuldson 51a78e8b8a add a quick settings menu for timeline headers 2021-02-25 10:56:16 +02:00
Shpuld Shpuldson ecb211606c change config comment to be consistent 2021-02-23 10:06:45 +02:00
Shpuld Shpuldson 29dae3c12e update changelog 2021-02-23 10:03:29 +02:00
Shpuld Shpuldson 3f23aecd10 add sensitive by default option 2021-02-23 10:00:23 +02:00
Shpuld Shpuldson 485f4b899c changelog conflict 2021-02-22 18:11:27 +02:00
Shpuld Shpuldson 98cb9abac7 Add timeline menu toggle to nav panel 2021-02-22 16:24:04 +02:00
Henry Jameson 9a8bc245a6 fixed few-posts TLs when streaming is enabled 2021-01-13 22:17:29 +02:00
Henry Jameson 48bef143d8 fix not being able to re-enable sockets until page refresh 2021-01-13 21:33:20 +02:00
Henry Jameson 64fa662644 added notices for ws events 2021-01-13 21:32:25 +02:00
Henry Jameson adc3b17fe0 add success global notice style/level 2021-01-13 21:29:12 +02:00
Henry Jameson 835eaf33b1 fix local dev websockets 2021-01-13 21:28:34 +02:00
188 changed files with 8734 additions and 2979 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
{ {
"presets": ["@babel/preset-env"], "presets": ["@babel/preset-env", "@vue/babel-preset-jsx"],
"plugins": ["@babel/plugin-transform-runtime", "lodash", "@vue/babel-plugin-transform-vue-jsx"], "plugins": ["@babel/plugin-transform-runtime", "lodash"],
"comments": false "comments": false
} }
+33
View File
@@ -3,6 +3,32 @@ 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.4.2] - 2022-01-09
### Added
- Added Apply and Reset buttons to the bottom of theme tab to minimize UI travel
- Implemented user option to always show floating New Post button (normally mobile-only)
- Display reasons for instance specific policies
- Added functionality to cancel follow request
### Fixed
- Fixed link to external profile not working on user profiles
- Fixed mobile shoutbox display
- Fixed favicon badge not working in Chrome
- Escape html more properly in subject/display name
## [2.4.0] - 2021-08-08
### Added
- Added a quick settings to timeline header for easier access
- Added option to mark posts as sensitive by default
- Added quick filters for notifications
- Implemented user option to change sidebar position to the right side
- Implemented user option to hide floating shout panel
- Implemented "edit profile" button if viewing own profile which opens profile settings
### Fixed
- Fixed follow request count showing in the wrong location in mobile view
## [2.3.0] - 2021-03-01 ## [2.3.0] - 2021-03-01
### Fixed ### Fixed
@@ -12,9 +38,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fixed some UI jumpiness when opening images particularly in chat view - Fixed some UI jumpiness when opening images particularly in chat view
- Fixed chat unread badge looking weird - Fixed chat unread badge looking weird
- Fixed punycode names not working properly - Fixed punycode names not working properly
- Fixed notifications crashing on an invalid notification
### Changed ### Changed
- Display 'people voted' instead of 'votes' for multi-choice polls - Display 'people voted' instead of 'votes' for multi-choice polls
- Changed the "Timelines" link in side panel to toggle show all timeline options inside the panel
- Renamed "Timeline" to "Home Timeline" to be more clear
- Optimized chat to not get horrible performance after keeping the same chat open for a long time - Optimized chat to not get horrible performance after keeping the same chat open for a long time
- When opening emoji picker or react picker, it automatically focuses the search field - When opening emoji picker or react picker, it automatically focuses the search field
- Language picker now uses native language names - Language picker now uses native language names
@@ -31,6 +60,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed ### Fixed
- Follows/Followers tabs on user profiles now display the content properly. - Follows/Followers tabs on user profiles now display the content properly.
- Handle punycode in screen names - Handle punycode in screen names
- Fixed local dev mode having non-functional websockets in some cases
- Show notices for websocket events (errors, abnormal closures, reconnections)
- Fix not being able to re-enable websocket until page refresh
- Fix annoying issue where timeline might have few posts when streaming is enabled
### Changed ### Changed
- Don't filter own posts when they hit your wordfilter - Don't filter own posts when they hit your wordfilter
+1
View File
@@ -3,6 +3,7 @@ Contributors of this project.
- Constance Variable (lambadalambda@social.heldscal.la): Code - Constance Variable (lambadalambda@social.heldscal.la): Code
- Coco Snuss (cocosnuss@social.heldscal.la): Code - Coco Snuss (cocosnuss@social.heldscal.la): Code
- wakarimasen (wakarimasen@shitposter.club): NSFW hiding image - wakarimasen (wakarimasen@shitposter.club): NSFW hiding image
- eris (eris@disqordia.space): Code
- dtluna (dtluna@social.heldscal.la): Code - dtluna (dtluna@social.heldscal.la): Code
- sonyam (sonyam@social.heldscal.la): Background images - sonyam (sonyam@social.heldscal.la): Background images
- hakui (hakui@freezepeach.xyz): CSS and styling - hakui (hakui@freezepeach.xyz): CSS and styling
+1
View File
@@ -21,6 +21,7 @@ var compiler = webpack(webpackConfig)
var devMiddleware = require('webpack-dev-middleware')(compiler, { var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath, publicPath: webpackConfig.output.publicPath,
writeToDisk: true,
stats: { stats: {
colors: true, colors: true,
chunks: false chunks: false
+14
View File
@@ -3,6 +3,7 @@ var config = require('../config')
var utils = require('./utils') var utils = require('./utils')
var projectRoot = path.resolve(__dirname, '../') var projectRoot = path.resolve(__dirname, '../')
var ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin') var ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin')
var CopyPlugin = require('copy-webpack-plugin');
var env = process.env.NODE_ENV var env = process.env.NODE_ENV
// check env & config/index.js to decide weither to enable CSS Sourcemaps for the // check env & config/index.js to decide weither to enable CSS Sourcemaps for the
@@ -93,6 +94,19 @@ module.exports = {
new ServiceWorkerWebpackPlugin({ new ServiceWorkerWebpackPlugin({
entry: path.join(__dirname, '..', 'src/sw.js'), entry: path.join(__dirname, '..', 'src/sw.js'),
filename: 'sw-pleroma.js' filename: 'sw-pleroma.js'
}),
// This copies Ruffle's WASM to a directory so that JS side can access it
new CopyPlugin({
patterns: [
{
from: "node_modules/ruffle-mirror/*",
to: "static/ruffle",
flatten: true
},
],
options: {
concurrency: 100,
},
}) })
] ]
} }
+5
View File
@@ -3,6 +3,11 @@ const path = require('path')
let settings = {} let settings = {}
try { try {
settings = require('./local.json') settings = require('./local.json')
if (settings.target && settings.target.endsWith('/')) {
// replacing trailing slash since it can conflict with some apis
// and that's how actual BE reports its url
settings.target = settings.target.replace(/\/$/, '')
}
console.log('Using local dev server settings (/config/local.json):') console.log('Using local dev server settings (/config/local.json):')
console.log(JSON.stringify(settings, null, 2)) console.log(JSON.stringify(settings, null, 2))
} catch (e) { } catch (e) {
+5 -4
View File
@@ -32,9 +32,9 @@
"phoenix": "^1.3.0", "phoenix": "^1.3.0",
"portal-vue": "^2.1.4", "portal-vue": "^2.1.4",
"punycode.js": "^2.1.0", "punycode.js": "^2.1.0",
"ruffle-mirror": "^2021.4.10",
"v-click-outside": "^2.1.1", "v-click-outside": "^2.1.1",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-chat-scroll": "^1.2.1",
"vue-i18n": "^7.3.2", "vue-i18n": "^7.3.2",
"vue-router": "^3.0.1", "vue-router": "^3.0.1",
"vue-template-compiler": "^2.6.11", "vue-template-compiler": "^2.6.11",
@@ -47,8 +47,8 @@
"@babel/preset-env": "^7.7.6", "@babel/preset-env": "^7.7.6",
"@babel/register": "^7.7.4", "@babel/register": "^7.7.4",
"@ungap/event-target": "^0.1.0", "@ungap/event-target": "^0.1.0",
"@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", "@vue/babel-helper-vue-jsx-merge-props": "^1.2.1",
"@vue/babel-plugin-transform-vue-jsx": "^1.1.2", "@vue/babel-preset-jsx": "^1.2.4",
"@vue/test-utils": "^1.0.0-beta.26", "@vue/test-utils": "^1.0.0-beta.26",
"autoprefixer": "^6.4.0", "autoprefixer": "^6.4.0",
"babel-eslint": "^7.0.0", "babel-eslint": "^7.0.0",
@@ -58,6 +58,7 @@
"chalk": "^1.1.3", "chalk": "^1.1.3",
"chromedriver": "^87.0.1", "chromedriver": "^87.0.1",
"connect-history-api-fallback": "^1.1.0", "connect-history-api-fallback": "^1.1.0",
"copy-webpack-plugin": "^6.4.1",
"cross-spawn": "^4.0.2", "cross-spawn": "^4.0.2",
"css-loader": "^0.28.0", "css-loader": "^0.28.0",
"custom-event-polyfill": "^1.0.7", "custom-event-polyfill": "^1.0.7",
@@ -112,7 +113,7 @@
"url-loader": "^1.1.2", "url-loader": "^1.1.2",
"vue-loader": "^14.0.0", "vue-loader": "^14.0.0",
"vue-style-loader": "^4.0.0", "vue-style-loader": "^4.0.0",
"webpack": "^4.0.0", "webpack": "^4.44.0",
"webpack-dev-middleware": "^3.6.0", "webpack-dev-middleware": "^3.6.0",
"webpack-hot-middleware": "^2.12.2", "webpack-hot-middleware": "^2.12.2",
"webpack-merge": "^0.14.1" "webpack-merge": "^0.14.1"
+10 -4
View File
@@ -4,7 +4,7 @@ import Notifications from './components/notifications/notifications.vue'
import InstanceSpecificPanel from './components/instance_specific_panel/instance_specific_panel.vue' import InstanceSpecificPanel from './components/instance_specific_panel/instance_specific_panel.vue'
import FeaturesPanel from './components/features_panel/features_panel.vue' import FeaturesPanel from './components/features_panel/features_panel.vue'
import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue' import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue'
import ChatPanel from './components/chat_panel/chat_panel.vue' import ShoutPanel from './components/shout_panel/shout_panel.vue'
import SettingsModal from './components/settings_modal/settings_modal.vue' import SettingsModal from './components/settings_modal/settings_modal.vue'
import MediaModal from './components/media_modal/media_modal.vue' import MediaModal from './components/media_modal/media_modal.vue'
import SideDrawer from './components/side_drawer/side_drawer.vue' import SideDrawer from './components/side_drawer/side_drawer.vue'
@@ -26,7 +26,7 @@ export default {
InstanceSpecificPanel, InstanceSpecificPanel,
FeaturesPanel, FeaturesPanel,
WhoToFollowPanel, WhoToFollowPanel,
ChatPanel, ShoutPanel,
MediaModal, MediaModal,
SideDrawer, SideDrawer,
MobilePostStatusButton, MobilePostStatusButton,
@@ -65,7 +65,7 @@ export default {
} }
} }
}, },
chat () { return this.$store.state.chat.channel.state === 'joined' }, shout () { return this.$store.state.shout.channel.state === '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 &&
@@ -73,11 +73,17 @@ export default {
this.$store.state.instance.instanceSpecificPanelContent this.$store.state.instance.instanceSpecificPanelContent
}, },
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel }, showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
shoutboxPosition () {
return this.$store.getters.mergedConfig.showNewPostButton || false
},
hideShoutbox () {
return this.$store.getters.mergedConfig.hideShoutbox
},
isMobileLayout () { return this.$store.state.interface.mobileLayout }, isMobileLayout () { return this.$store.state.interface.mobileLayout },
privateMode () { return this.$store.state.instance.private }, privateMode () { return this.$store.state.instance.private },
sidebarAlign () { sidebarAlign () {
return { return {
'order': this.$store.state.instance.sidebarRight ? 99 : 0 'order': this.$store.getters.mergedConfig.sidebarRight ? 99 : 0
} }
}, },
...mapGetters(['mergedConfig']) ...mapGetters(['mergedConfig'])
+29 -53
View File
@@ -88,6 +88,10 @@ a {
font-family: sans-serif; font-family: sans-serif;
font-family: var(--interfaceFont, sans-serif); font-family: var(--interfaceFont, sans-serif);
&.-sublime {
background: transparent;
}
i[class*=icon-], i[class*=icon-],
.svg-inline--fa { .svg-inline--fa {
color: $fallback--text; color: $fallback--text;
@@ -187,7 +191,7 @@ a {
} }
} }
input, textarea, .select, .input { input, textarea, .input {
&.unstyled { &.unstyled {
border-radius: 0; border-radius: 0;
@@ -217,47 +221,11 @@ input, textarea, .select, .input {
hyphens: none; hyphens: none;
padding: 8px .5em; padding: 8px .5em;
&.select { &:disabled, &[disabled=disabled], &.disabled {
padding: 0;
}
&:disabled, &[disabled=disabled] {
cursor: not-allowed; cursor: not-allowed;
opacity: 0.5; opacity: 0.5;
} }
.select-down-icon {
position: absolute;
top: 0;
bottom: 0;
right: 5px;
height: 100%;
color: $fallback--text;
color: var(--inputText, $fallback--text);
line-height: 28px;
z-index: 0;
pointer-events: none;
}
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: transparent;
border: none;
color: $fallback--text;
color: var(--inputText, --text, $fallback--text);
margin: 0;
padding: 0 2em 0 .2em;
font-family: sans-serif;
font-family: var(--inputFont, sans-serif);
font-size: 14px;
width: 100%;
z-index: 1;
height: 28px;
line-height: 16px;
}
&[type=range] { &[type=range] {
background: none; background: none;
border: none; border: none;
@@ -547,9 +515,21 @@ main-router {
border-radius: var(--panelRadius, $fallback--panelRadius); border-radius: var(--panelRadius, $fallback--panelRadius);
} }
.panel-footer { /* TODO Should remove timeline-footer from here when we refactor panels into
* separate component and utilize slots
*/
.panel-footer, .timeline-footer {
display: flex;
border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius; border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius); border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
flex: none;
padding: 0.6em 0.6em;
text-align: left;
line-height: 28px;
align-items: baseline;
border-width: 1px 0 0 0;
border-style: solid;
border-color: var(--border, $fallback--border);
.faint { .faint {
color: $fallback--faint; color: $fallback--faint;
@@ -706,6 +686,15 @@ nav {
color: var(--alertWarningPanelText, $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 {
@@ -809,13 +798,6 @@ nav {
} }
} }
.select-multiple {
display: flex;
.option-list {
margin: 0;
padding-left: .5em;
}
}
.setting-list, .setting-list,
.option-list{ .option-list{
list-style-type: none; list-style-type: none;
@@ -863,15 +845,9 @@ nav {
.new-status-notification { .new-status-notification {
position: relative; position: relative;
margin-top: -1px;
font-size: 1.1em; font-size: 1.1em;
border-width: 1px 0 0 0;
border-style: solid;
border-color: var(--border, $fallback--border);
padding: 10px;
z-index: 1; z-index: 1;
background-color: $fallback--fg; flex: 1;
background-color: var(--panel, $fallback--fg);
} }
.chat-layout { .chat-layout {
+4 -3
View File
@@ -49,10 +49,11 @@
</div> </div>
<media-modal /> <media-modal />
</div> </div>
<chat-panel <shout-panel
v-if="currentUser && chat" v-if="currentUser && shout && !hideShoutbox"
:floating="true" :floating="true"
class="floating-chat mobile-hidden" class="floating-shout mobile-hidden"
:class="{ 'left': shoutboxPosition }"
/> />
<MobilePostStatusButton /> <MobilePostStatusButton />
<UserReportingModal /> <UserReportingModal />
+1 -1
View File
@@ -240,7 +240,7 @@ const getNodeInfo = async ({ store }) => {
store.dispatch('setInstanceOption', { name: 'registrationOpen', value: data.openRegistrations }) store.dispatch('setInstanceOption', { name: 'registrationOpen', value: data.openRegistrations })
store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: features.includes('media_proxy') }) store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: features.includes('media_proxy') })
store.dispatch('setInstanceOption', { name: 'safeDM', value: features.includes('safe_dm_mentions') }) store.dispatch('setInstanceOption', { name: 'safeDM', value: features.includes('safe_dm_mentions') })
store.dispatch('setInstanceOption', { name: 'chatAvailable', value: features.includes('chat') }) store.dispatch('setInstanceOption', { name: 'shoutAvailable', value: features.includes('chat') })
store.dispatch('setInstanceOption', { name: 'pleromaChatMessagesAvailable', value: features.includes('pleroma_chat_messages') }) store.dispatch('setInstanceOption', { name: 'pleromaChatMessagesAvailable', value: features.includes('pleroma_chat_messages') })
store.dispatch('setInstanceOption', { name: 'gopherAvailable', value: features.includes('gopher') }) store.dispatch('setInstanceOption', { name: 'gopherAvailable', value: features.includes('gopher') })
store.dispatch('setInstanceOption', { name: 'pollsAvailable', value: features.includes('polls') }) store.dispatch('setInstanceOption', { name: 'pollsAvailable', value: features.includes('polls') })
+2 -2
View File
@@ -16,7 +16,7 @@ import FollowRequests from 'components/follow_requests/follow_requests.vue'
import OAuthCallback from 'components/oauth_callback/oauth_callback.vue' import OAuthCallback from 'components/oauth_callback/oauth_callback.vue'
import Notifications from 'components/notifications/notifications.vue' import Notifications from 'components/notifications/notifications.vue'
import AuthForm from 'components/auth_form/auth_form.js' import AuthForm from 'components/auth_form/auth_form.js'
import ChatPanel from 'components/chat_panel/chat_panel.vue' import ShoutPanel from 'components/shout_panel/shout_panel.vue'
import WhoToFollow from 'components/who_to_follow/who_to_follow.vue' import WhoToFollow from 'components/who_to_follow/who_to_follow.vue'
import About from 'components/about/about.vue' import About from 'components/about/about.vue'
import RemoteUserResolver from 'components/remote_user_resolver/remote_user_resolver.vue' import RemoteUserResolver from 'components/remote_user_resolver/remote_user_resolver.vue'
@@ -64,7 +64,7 @@ export default (store) => {
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests, beforeEnter: validateAuthenticatedRoute }, { name: 'friend-requests', path: '/friend-requests', component: FollowRequests, beforeEnter: validateAuthenticatedRoute },
{ name: 'notifications', path: '/:username/notifications', component: Notifications, beforeEnter: validateAuthenticatedRoute }, { name: 'notifications', path: '/:username/notifications', component: Notifications, beforeEnter: validateAuthenticatedRoute },
{ name: 'login', path: '/login', component: AuthForm }, { name: 'login', path: '/login', component: AuthForm },
{ name: 'chat-panel', path: '/chat-panel', component: ChatPanel, props: () => ({ floating: false }) }, { name: 'shout-panel', path: '/shout-panel', component: ShoutPanel, props: () => ({ floating: false }) },
{ name: 'oauth-callback', path: '/oauth-callback', component: OAuthCallback, props: (route) => ({ code: route.query.code }) }, { name: 'oauth-callback', path: '/oauth-callback', component: OAuthCallback, props: (route) => ({ code: route.query.code }) },
{ name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) }, { name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) },
{ name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute }, { name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute },
@@ -6,10 +6,7 @@
:bound-to="{ x: 'container' }" :bound-to="{ x: 'container' }"
remove-padding remove-padding
> >
<div <template v-slot:content>
slot="content"
class="account-tools-popover"
>
<div class="dropdown-menu"> <div class="dropdown-menu">
<template v-if="relationship.following"> <template v-if="relationship.following">
<button <button
@@ -59,16 +56,15 @@
{{ $t('user_card.message') }} {{ $t('user_card.message') }}
</button> </button>
</div> </div>
</div> </template>
<div <template v-slot:trigger>
slot="trigger" <button class="button-unstyled ellipsis-button">
class="ellipsis-button"
>
<FAIcon <FAIcon
class="icon" class="icon"
icon="ellipsis-v" icon="ellipsis-v"
/> />
</div> </button>
</template>
</Popover> </Popover>
</div> </div>
</template> </template>
@@ -83,7 +79,6 @@
} }
.ellipsis-button { .ellipsis-button {
cursor: pointer;
width: 2.5em; width: 2.5em;
margin: -0.5em 0; margin: -0.5em 0;
padding: 0.5em 0; padding: 0.5em 0;
+2
View File
@@ -1,4 +1,5 @@
import StillImage from '../still-image/still-image.vue' import StillImage from '../still-image/still-image.vue'
import Flash from '../flash/flash.vue'
import VideoAttachment from '../video_attachment/video_attachment.vue' import VideoAttachment from '../video_attachment/video_attachment.vue'
import nsfwImage from '../../assets/nsfw.png' import nsfwImage from '../../assets/nsfw.png'
import fileTypeService from '../../services/file_type/file_type.service.js' import fileTypeService from '../../services/file_type/file_type.service.js'
@@ -43,6 +44,7 @@ const Attachment = {
} }
}, },
components: { components: {
Flash,
StillImage, StillImage,
VideoAttachment VideoAttachment
}, },
+6
View File
@@ -117,6 +117,11 @@
<!-- eslint-enable vue/no-v-html --> <!-- eslint-enable vue/no-v-html -->
</div> </div>
</div> </div>
<Flash
v-if="type === 'flash'"
:src="attachment.large_thumb_url || attachment.url"
/>
</div> </div>
</template> </template>
@@ -172,6 +177,7 @@
} }
.non-gallery.attachment { .non-gallery.attachment {
&.flash,
&.video { &.video {
flex: 1 0 40%; flex: 1 0 40%;
} }
@@ -1,5 +1,6 @@
import UserCard from '../user_card/user_card.vue' import UserCard from '../user_card/user_card.vue'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
const BasicUserCard = { const BasicUserCard = {
@@ -13,7 +14,8 @@ const BasicUserCard = {
}, },
components: { components: {
UserCard, UserCard,
UserAvatar UserAvatar,
RichContent
}, },
methods: { methods: {
toggleUserExpanded () { toggleUserExpanded () {
@@ -25,17 +25,11 @@
:title="user.name" :title="user.name"
class="basic-user-card-user-name" class="basic-user-card-user-name"
> >
<!-- eslint-disable vue/no-v-html --> <RichContent
<span
v-if="user.name_html"
class="basic-user-card-user-name-value" class="basic-user-card-user-name-value"
v-html="user.name_html" :html="user.name"
:emoji="user.emoji"
/> />
<!-- eslint-enable vue/no-v-html -->
<span
v-else
class="basic-user-card-user-name-value"
>{{ user.name }}</span>
</div> </div>
<div> <div>
<router-link <router-link
+1 -4
View File
@@ -23,10 +23,7 @@
class="timeline" class="timeline"
> >
<List :items="sortedChatList"> <List :items="sortedChatList">
<template <template v-slot:item="{item}">
slot="item"
slot-scope="{item}"
>
<ChatListItem <ChatListItem
:key="item.id" :key="item.id"
:compact="false" :compact="false"
@@ -1,5 +1,5 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
import StatusContent from '../status_content/status_content.vue' import StatusBody from '../status_content/status_content.vue'
import fileType from 'src/services/file_type/file_type.service' import fileType from 'src/services/file_type/file_type.service'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
import AvatarList from '../avatar_list/avatar_list.vue' import AvatarList from '../avatar_list/avatar_list.vue'
@@ -16,7 +16,7 @@ const ChatListItem = {
AvatarList, AvatarList,
Timeago, Timeago,
ChatTitle, ChatTitle,
StatusContent StatusBody
}, },
computed: { computed: {
...mapState({ ...mapState({
@@ -38,12 +38,14 @@ const ChatListItem = {
}, },
messageForStatusContent () { messageForStatusContent () {
const message = this.chat.lastMessage const message = this.chat.lastMessage
const messageEmojis = message ? message.emojis : []
const isYou = message && message.account_id === this.currentUser.id const isYou = message && message.account_id === this.currentUser.id
const content = message ? (this.attachmentInfo || message.content) : '' const content = message ? (this.attachmentInfo || message.content) : ''
const messagePreview = isYou ? `<i>${this.$t('chats.you')}</i> ${content}` : content const messagePreview = isYou ? `<i>${this.$t('chats.you')}</i> ${content}` : content
return { return {
summary: '', summary: '',
statusnet_html: messagePreview, emojis: messageEmojis,
raw_html: messagePreview,
text: messagePreview, text: messagePreview,
attachments: [] attachments: []
} }
@@ -77,18 +77,15 @@
border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
} }
.StatusContent { .chat-preview-body {
img.emoji { --emoji-size: 1.4em;
width: 1.4em;
height: 1.4em;
}
} }
.time-wrapper { .time-wrapper {
line-height: 1.4em; line-height: 1.4em;
} }
.single-line { .chat-preview-body {
padding-right: 1em; padding-right: 1em;
} }
} }
@@ -29,7 +29,8 @@
</div> </div>
</div> </div>
<div class="chat-preview"> <div class="chat-preview">
<StatusContent <StatusBody
class="chat-preview-body"
:status="messageForStatusContent" :status="messageForStatusContent"
:single-line="true" :single-line="true"
/> />
+3 -2
View File
@@ -57,8 +57,9 @@ const ChatMessage = {
messageForStatusContent () { messageForStatusContent () {
return { return {
summary: '', summary: '',
statusnet_html: this.message.content, emojis: this.message.emojis,
text: this.message.content, raw_html: this.message.content || '',
text: this.message.content || '',
attachments: this.message.attachments attachments: this.message.attachments
} }
}, },
@@ -89,8 +89,9 @@
} }
.without-attachment { .without-attachment {
.status-content { .message-content {
&::after { // TODO figure out how to do it properly
.RichContent::after {
margin-right: 5.4em; margin-right: 5.4em;
content: " "; content: " ";
display: inline-block; display: inline-block;
@@ -162,6 +163,7 @@
.visible { .visible {
opacity: 1; opacity: 1;
} }
} }
.chat-message-date-separator { .chat-message-date-separator {
+7 -4
View File
@@ -50,7 +50,7 @@
@show="menuOpened = true" @show="menuOpened = true"
@close="menuOpened = false" @close="menuOpened = false"
> >
<div slot="content"> <template v-slot:content>
<div class="dropdown-menu"> <div class="dropdown-menu">
<button <button
class="button-default dropdown-item dropdown-item-icon" class="button-default dropdown-item dropdown-item-icon"
@@ -59,26 +59,29 @@
<FAIcon icon="times" /> {{ $t("chats.delete") }} <FAIcon icon="times" /> {{ $t("chats.delete") }}
</button> </button>
</div> </div>
</div> </template>
<template v-slot:trigger>
<button <button
slot="trigger"
class="button-default menu-icon" class="button-default menu-icon"
:title="$t('chats.more')" :title="$t('chats.more')"
> >
<FAIcon icon="ellipsis-h" /> <FAIcon icon="ellipsis-h" />
</button> </button>
</template>
</Popover> </Popover>
</div> </div>
<StatusContent <StatusContent
class="message-content"
:status="messageForStatusContent" :status="messageForStatusContent"
:full-content="true" :full-content="true"
> >
<template v-slot:footer>
<span <span
slot="footer"
class="created-at" class="created-at"
> >
{{ createdAt }} {{ createdAt }}
</span> </span>
</template>
</StatusContent> </StatusContent>
</div> </div>
</div> </div>
@@ -9,7 +9,7 @@
class="btn button-default" class="btn button-default"
> >
{{ $t('domain_mute_card.unmute') }} {{ $t('domain_mute_card.unmute') }}
<template slot="progress"> <template v-slot:progress>
{{ $t('domain_mute_card.unmute_progress') }} {{ $t('domain_mute_card.unmute_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
@@ -19,7 +19,7 @@
class="btn button-default" class="btn button-default"
> >
{{ $t('domain_mute_card.mute') }} {{ $t('domain_mute_card.mute') }}
<template slot="progress"> <template v-slot:progress>
{{ $t('domain_mute_card.mute_progress') }} {{ $t('domain_mute_card.mute_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
+30 -30
View File
@@ -57,6 +57,7 @@ const EmojiInput = {
required: true, required: true,
type: Function type: Function
}, },
// TODO VUE3: change to modelValue, change 'input' event to 'input'
value: { value: {
/** /**
* Used for v-model * Used for v-model
@@ -143,32 +144,31 @@ const EmojiInput = {
} }
}, },
mounted () { mounted () {
const slots = this.$slots.default const { root } = this.$refs
if (!slots || slots.length === 0) return const input = root.querySelector('.emoji-input > input') || root.querySelector('.emoji-input > textarea')
const input = slots.find(slot => ['input', 'textarea'].includes(slot.tag))
if (!input) return if (!input) return
this.input = input this.input = input
this.resize() this.resize()
input.elm.addEventListener('blur', this.onBlur) input.addEventListener('blur', this.onBlur)
input.elm.addEventListener('focus', this.onFocus) input.addEventListener('focus', this.onFocus)
input.elm.addEventListener('paste', this.onPaste) input.addEventListener('paste', this.onPaste)
input.elm.addEventListener('keyup', this.onKeyUp) input.addEventListener('keyup', this.onKeyUp)
input.elm.addEventListener('keydown', this.onKeyDown) input.addEventListener('keydown', this.onKeyDown)
input.elm.addEventListener('click', this.onClickInput) input.addEventListener('click', this.onClickInput)
input.elm.addEventListener('transitionend', this.onTransition) input.addEventListener('transitionend', this.onTransition)
input.elm.addEventListener('input', this.onInput) input.addEventListener('input', this.onInput)
}, },
unmounted () { unmounted () {
const { input } = this const { input } = this
if (input) { if (input) {
input.elm.removeEventListener('blur', this.onBlur) input.removeEventListener('blur', this.onBlur)
input.elm.removeEventListener('focus', this.onFocus) input.removeEventListener('focus', this.onFocus)
input.elm.removeEventListener('paste', this.onPaste) input.removeEventListener('paste', this.onPaste)
input.elm.removeEventListener('keyup', this.onKeyUp) input.removeEventListener('keyup', this.onKeyUp)
input.elm.removeEventListener('keydown', this.onKeyDown) input.removeEventListener('keydown', this.onKeyDown)
input.elm.removeEventListener('click', this.onClickInput) input.removeEventListener('click', this.onClickInput)
input.elm.removeEventListener('transitionend', this.onTransition) input.removeEventListener('transitionend', this.onTransition)
input.elm.removeEventListener('input', this.onInput) input.removeEventListener('input', this.onInput)
} }
}, },
watch: { watch: {
@@ -216,7 +216,7 @@ const EmojiInput = {
}, 0) }, 0)
}, },
togglePicker () { togglePicker () {
this.input.elm.focus() this.input.focus()
this.showPicker = !this.showPicker this.showPicker = !this.showPicker
if (this.showPicker) { if (this.showPicker) {
this.scrollIntoView() this.scrollIntoView()
@@ -262,13 +262,13 @@ const EmojiInput = {
this.$emit('input', newValue) this.$emit('input', newValue)
const position = this.caret + (insertion + spaceAfter + spaceBefore).length const position = this.caret + (insertion + spaceAfter + spaceBefore).length
if (!keepOpen) { if (!keepOpen) {
this.input.elm.focus() this.input.focus()
} }
this.$nextTick(function () { this.$nextTick(function () {
// Re-focus inputbox after clicking suggestion // Re-focus inputbox after clicking suggestion
// Set selection right after the replacement instead of the very end // Set selection right after the replacement instead of the very end
this.input.elm.setSelectionRange(position, position) this.input.setSelectionRange(position, position)
this.caret = position this.caret = position
}) })
}, },
@@ -285,9 +285,9 @@ const EmojiInput = {
this.$nextTick(function () { this.$nextTick(function () {
// Re-focus inputbox after clicking suggestion // Re-focus inputbox after clicking suggestion
this.input.elm.focus() this.input.focus()
// Set selection right after the replacement instead of the very end // Set selection right after the replacement instead of the very end
this.input.elm.setSelectionRange(position, position) this.input.setSelectionRange(position, position)
this.caret = position this.caret = position
}) })
e.preventDefault() e.preventDefault()
@@ -349,7 +349,7 @@ const EmojiInput = {
} }
this.$nextTick(() => { this.$nextTick(() => {
const { offsetHeight } = this.input.elm const { offsetHeight } = this.input
const { picker } = this.$refs const { picker } = this.$refs
const pickerBottom = picker.$el.getBoundingClientRect().bottom const pickerBottom = picker.$el.getBoundingClientRect().bottom
if (pickerBottom > window.innerHeight) { if (pickerBottom > window.innerHeight) {
@@ -414,8 +414,8 @@ const EmojiInput = {
// Scroll the input element to the position of the cursor // Scroll the input element to the position of the cursor
this.$nextTick(() => { this.$nextTick(() => {
this.input.elm.blur() this.input.blur()
this.input.elm.focus() this.input.focus()
}) })
} }
// Disable suggestions hotkeys if suggestions are hidden // Disable suggestions hotkeys if suggestions are hidden
@@ -444,7 +444,7 @@ const EmojiInput = {
// de-focuses the element (i.e. default browser behavior) // de-focuses the element (i.e. default browser behavior)
if (key === 'Escape') { if (key === 'Escape') {
if (!this.temporarilyHideSuggestions) { if (!this.temporarilyHideSuggestions) {
this.input.elm.focus() this.input.focus()
} }
} }
@@ -480,7 +480,7 @@ const EmojiInput = {
if (!panel) return if (!panel) return
const picker = this.$refs.picker.$el const picker = this.$refs.picker.$el
const panelBody = this.$refs['panel-body'] const panelBody = this.$refs['panel-body']
const { offsetHeight, offsetTop } = this.input.elm const { offsetHeight, offsetTop } = this.input
const offsetBottom = offsetTop + offsetHeight const offsetBottom = offsetTop + offsetHeight
this.setPlacement(panelBody, panel, offsetBottom) this.setPlacement(panelBody, panel, offsetBottom)
@@ -494,7 +494,7 @@ const EmojiInput = {
if (this.placement === 'top' || (this.placement === 'auto' && this.overflowsBottom(container))) { if (this.placement === 'top' || (this.placement === 'auto' && this.overflowsBottom(container))) {
target.style.top = 'auto' target.style.top = 'auto'
target.style.bottom = this.input.elm.offsetHeight + 'px' target.style.bottom = this.input.offsetHeight + 'px'
} }
}, },
overflowsBottom (el) { overflowsBottom (el) {
@@ -1,5 +1,6 @@
<template> <template>
<div <div
ref="root"
v-click-outside="onClickOutside" v-click-outside="onClickOutside"
class="emoji-input" class="emoji-input"
:class="{ 'with-picker': !hideEmojiButton }" :class="{ 'with-picker': !hideEmojiButton }"
@@ -1,102 +0,0 @@
<template>
<div class="import-export-container">
<slot name="before" />
<button
class="btn button-default"
@click="exportData"
>
{{ exportLabel }}
</button>
<button
class="btn button-default"
@click="importData"
>
{{ importLabel }}
</button>
<slot name="afterButtons" />
<p
v-if="importFailed"
class="alert error"
>
{{ importFailedText }}
</p>
<slot name="afterError" />
</div>
</template>
<script>
export default {
props: [
'exportObject',
'importLabel',
'exportLabel',
'importFailedText',
'validator',
'onImport',
'onImportFailure'
],
data () {
return {
importFailed: false
}
},
methods: {
exportData () {
const stringified = JSON.stringify(this.exportObject, null, 2) // Pretty-print and indent with 2 spaces
// Create an invisible link with a data url and simulate a click
const e = document.createElement('a')
e.setAttribute('download', 'pleroma_theme.json')
e.setAttribute('href', 'data:application/json;base64,' + window.btoa(stringified))
e.style.display = 'none'
document.body.appendChild(e)
e.click()
document.body.removeChild(e)
},
importData () {
this.importFailed = false
const filePicker = document.createElement('input')
filePicker.setAttribute('type', 'file')
filePicker.setAttribute('accept', '.json')
filePicker.addEventListener('change', event => {
if (event.target.files[0]) {
// eslint-disable-next-line no-undef
const reader = new FileReader()
reader.onload = ({ target }) => {
try {
const parsed = JSON.parse(target.result)
const valid = this.validator(parsed)
if (valid) {
this.onImport(parsed)
} else {
this.importFailed = true
// this.onImportFailure(valid)
}
} catch (e) {
// This will happen both if there is a JSON syntax error or the theme is missing components
this.importFailed = true
// this.onImportFailure(e)
}
}
reader.readAsText(event.target.files[0])
}
})
document.body.appendChild(filePicker)
filePicker.click()
document.body.removeChild(filePicker)
}
}
}
</script>
<style lang="scss">
.import-export-container {
display: flex;
flex-wrap: wrap;
align-items: baseline;
justify-content: center;
}
</style>
+6 -10
View File
@@ -7,10 +7,7 @@
:bound-to="{ x: 'container' }" :bound-to="{ x: 'container' }"
remove-padding remove-padding
> >
<div <template v-slot:content="{close}">
slot="content"
slot-scope="{close}"
>
<div class="dropdown-menu"> <div class="dropdown-menu">
<button <button
v-if="canMute && !status.thread_muted" v-if="canMute && !status.thread_muted"
@@ -120,16 +117,15 @@
/><span>{{ $t("user_card.report") }}</span> /><span>{{ $t("user_card.report") }}</span>
</button> </button>
</div> </div>
</div> </template>
<span <template v-slot:trigger>
slot="trigger" <button class="button-unstyled popover-trigger">
class="popover-trigger"
>
<FAIcon <FAIcon
class="fa-scale-110 fa-old-padding" class="fa-scale-110 fa-old-padding"
icon="ellipsis-h" icon="ellipsis-h"
/> />
</span> </button>
</template>
</Popover> </Popover>
</template> </template>
@@ -2,7 +2,7 @@ import fileSizeFormatService from '../../services/file_size_format/file_size_for
const FeaturesPanel = { const FeaturesPanel = {
computed: { computed: {
chat: function () { return this.$store.state.instance.chatAvailable }, shout: function () { return this.$store.state.instance.shoutAvailable },
pleromaChatMessages: function () { return this.$store.state.instance.pleromaChatMessagesAvailable }, pleromaChatMessages: function () { return this.$store.state.instance.pleromaChatMessagesAvailable },
gopher: function () { return this.$store.state.instance.gopherAvailable }, gopher: function () { return this.$store.state.instance.gopherAvailable },
whoToFollow: function () { return this.$store.state.instance.suggestionsEnabled }, whoToFollow: function () { return this.$store.state.instance.suggestionsEnabled },
@@ -8,8 +8,8 @@
</div> </div>
<div class="panel-body features-panel"> <div class="panel-body features-panel">
<ul> <ul>
<li v-if="chat"> <li v-if="shout">
{{ $t('features_panel.chat') }} {{ $t('features_panel.shout') }}
</li> </li>
<li v-if="pleromaChatMessages"> <li v-if="pleromaChatMessages">
{{ $t('features_panel.pleroma_chat_messages') }} {{ $t('features_panel.pleroma_chat_messages') }}
+52
View File
@@ -0,0 +1,52 @@
import RuffleService from '../../services/ruffle_service/ruffle_service.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faStop,
faExclamationTriangle
} from '@fortawesome/free-solid-svg-icons'
library.add(
faStop,
faExclamationTriangle
)
const Flash = {
props: [ 'src' ],
data () {
return {
player: false, // can be true, "hidden", false. hidden = element exists
loaded: false,
ruffleInstance: null
}
},
methods: {
openPlayer () {
if (this.player) return // prevent double-loading, or re-loading on failure
this.player = 'hidden'
RuffleService.getRuffle().then((ruffle) => {
const player = ruffle.newest().createPlayer()
player.config = {
letterbox: 'on'
}
const container = this.$refs.container
container.appendChild(player)
player.style.width = '100%'
player.style.height = '100%'
player.load(this.src).then(() => {
this.player = true
}).catch((e) => {
console.error('Error loading ruffle', e)
this.player = 'error'
})
this.ruffleInstance = player
})
},
closePlayer () {
console.log(this.ruffleInstance)
this.ruffleInstance.remove()
this.player = false
}
}
}
export default Flash
+88
View File
@@ -0,0 +1,88 @@
<template>
<div class="Flash">
<div
v-if="player === true || player === 'hidden'"
ref="container"
class="player"
:class="{ hidden: player === 'hidden' }"
/>
<button
v-if="player !== true"
class="button-unstyled placeholder"
@click="openPlayer"
>
<span
v-if="player === 'hidden'"
class="label"
>
{{ $t('general.loading') }}
</span>
<span
v-if="player === 'error'"
class="label"
>
{{ $t('general.flash_fail') }}
</span>
<span
v-else
class="label"
>
<p>
{{ $t('general.flash_content') }}
</p>
<p>
<FAIcon icon="exclamation-triangle" />
{{ $t('general.flash_security') }}
</p>
</span>
</button>
<button
v-if="player"
class="button-unstyled hider"
@click="closePlayer"
>
<FAIcon icon="stop" />
</button>
</div>
</template>
<script src="./flash.js"></script>
<style lang="scss">
@import '../../_variables.scss';
.Flash {
width: 100%;
height: 260px;
position: relative;
.player {
height: 100%;
width: 100%;
}
.hider {
top: 0;
}
.label {
text-align: center;
flex: 1 1 0;
line-height: 1.2;
white-space: normal;
word-wrap: normal;
}
.hidden {
display: none;
visibility: 'hidden';
}
.placeholder {
height: 100%;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
}
</style>
@@ -14,7 +14,7 @@ export default {
if (this.inProgress || this.relationship.following) { if (this.inProgress || this.relationship.following) {
return this.$t('user_card.follow_unfollow') return this.$t('user_card.follow_unfollow')
} else if (this.relationship.requested) { } else if (this.relationship.requested) {
return this.$t('user_card.follow_again') return this.$t('user_card.follow_cancel')
} else { } else {
return this.$t('user_card.follow') return this.$t('user_card.follow')
} }
@@ -33,7 +33,7 @@ export default {
}, },
methods: { methods: {
onClick () { onClick () {
this.relationship.following ? this.unfollow() : this.follow() this.relationship.following || this.relationship.requested ? this.unfollow() : this.follow()
}, },
follow () { follow () {
this.inProgress = true this.inProgress = true
+4 -8
View File
@@ -1,14 +1,10 @@
import { set } from 'vue' import { set } from 'vue'
import { library } from '@fortawesome/fontawesome-svg-core' import Select from '../select/select.vue'
import {
faChevronDown
} from '@fortawesome/free-solid-svg-icons'
library.add(
faChevronDown
)
export default { export default {
components: {
Select
},
props: [ props: [
'name', 'label', 'value', 'fallback', 'options', 'no-inherit' 'name', 'label', 'value', 'fallback', 'options', 'no-inherit'
], ],
+4 -13
View File
@@ -22,12 +22,7 @@
class="opt-l" class="opt-l"
:for="name + '-o'" :for="name + '-o'"
/> />
<label <Select
:for="name + '-font-switcher'"
class="select"
:disabled="!present"
>
<select
:id="name + '-font-switcher'" :id="name + '-font-switcher'"
v-model="preset" v-model="preset"
:disabled="!present" :disabled="!present"
@@ -40,12 +35,7 @@
> >
{{ option === 'custom' ? $t('settings.style.fonts.custom') : option }} {{ option === 'custom' ? $t('settings.style.fonts.custom') : option }}
</option> </option>
</select> </Select>
<FAIcon
class="select-down-icon"
icon="chevron-down"
/>
</label>
<input <input
v-if="isCustom" v-if="isCustom"
:id="name" :id="name"
@@ -65,7 +55,8 @@
min-width: 10em; min-width: 10em;
} }
&.custom { &.custom {
.select { /* TODO Should make proper joiners... */
.font-switcher {
border-top-right-radius: 0; border-top-right-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
} }
@@ -71,6 +71,14 @@
} }
} }
.global-success {
background-color: var(--alertPopupSuccess, $fallback--cGreen);
color: var(--alertPopupSuccessText, $fallback--text);
.svg-inline--fa {
color: var(--alertPopupSuccessText, $fallback--text);
}
}
.global-info { .global-info {
background-color: var(--alertPopupNeutral, $fallback--fg); background-color: var(--alertPopupNeutral, $fallback--fg);
color: var(--alertPopupNeutralText, $fallback--text); color: var(--alertPopupNeutralText, $fallback--text);
@@ -0,0 +1,36 @@
import { extractTagFromUrl } from 'src/services/matcher/matcher.service.js'
const HashtagLink = {
name: 'HashtagLink',
props: {
url: {
required: true,
type: String
},
content: {
required: true,
type: String
},
tag: {
required: false,
type: String,
default: ''
}
},
methods: {
onClick () {
const tag = this.tag || extractTagFromUrl(this.url)
if (tag) {
const link = this.generateTagLink(tag)
this.$router.push(link)
} else {
window.open(this.url, '_blank')
}
},
generateTagLink (tag) {
return `/tag/${tag}`
}
}
}
export default HashtagLink
@@ -0,0 +1,6 @@
.HashtagLink {
position: relative;
white-space: normal;
display: inline-block;
color: var(--link);
}
@@ -0,0 +1,19 @@
<template>
<span
class="HashtagLink"
>
<!-- eslint-disable vue/no-v-html -->
<a
:href="url"
class="original"
target="_blank"
@click.prevent="onClick"
v-html="content"
/>
<!-- eslint-enable vue/no-v-html -->
</span>
</template>
<script src="./hashtag_link.js"/>
<style lang="scss" src="./hashtag_link.scss"/>
@@ -3,11 +3,7 @@
<label for="interface-language-switcher"> <label for="interface-language-switcher">
{{ $t('settings.interfaceLanguage') }} {{ $t('settings.interfaceLanguage') }}
</label> </label>
<label <Select
for="interface-language-switcher"
class="select"
>
<select
id="interface-language-switcher" id="interface-language-switcher"
v-model="language" v-model="language"
> >
@@ -18,12 +14,7 @@
> >
{{ lang.name }} {{ lang.name }}
</option> </option>
</select> </Select>
<FAIcon
class="select-down-icon"
icon="chevron-down"
/>
</label>
</div> </div>
</template> </template>
@@ -32,16 +23,12 @@ import languagesObject from '../../i18n/messages'
import localeService from '../../services/locale/locale.service.js' import localeService from '../../services/locale/locale.service.js'
import ISO6391 from 'iso-639-1' import ISO6391 from 'iso-639-1'
import _ from 'lodash' import _ from 'lodash'
import { library } from '@fortawesome/fontawesome-svg-core' import Select from '../select/select.vue'
import {
faChevronDown
} from '@fortawesome/free-solid-svg-icons'
library.add(
faChevronDown
)
export default { export default {
components: {
Select
},
computed: { computed: {
languages () { languages () {
return _.map(languagesObject.languages, (code) => ({ code: code, name: this.getLanguageName(code) })).sort((a, b) => a.name.localeCompare(b.name)) return _.map(languagesObject.languages, (code) => ({ code: code, name: this.getLanguageName(code) })).sort((a, b) => a.name.localeCompare(b.name))
@@ -0,0 +1,95 @@
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { mapGetters, mapState } from 'vuex'
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faAt
} from '@fortawesome/free-solid-svg-icons'
library.add(
faAt
)
const MentionLink = {
name: 'MentionLink',
props: {
url: {
required: true,
type: String
},
content: {
required: true,
type: String
},
userId: {
required: false,
type: String
},
userScreenName: {
required: false,
type: String
}
},
methods: {
onClick () {
const link = generateProfileLink(
this.userId || this.user.id,
this.userScreenName || this.user.screen_name
)
this.$router.push(link)
}
},
computed: {
user () {
return this.url && this.$store && this.$store.getters.findUserByUrl(this.url)
},
isYou () {
// FIXME why user !== currentUser???
return this.user && this.user.id === this.currentUser.id
},
userName () {
return this.user && this.userNameFullUi.split('@')[0]
},
userNameFull () {
return this.user && this.user.screen_name
},
userNameFullUi () {
return this.user && this.user.screen_name_ui
},
highlight () {
return this.user && this.mergedConfig.highlight[this.user.screen_name]
},
highlightType () {
return this.highlight && ('-' + this.highlight.type)
},
highlightClass () {
if (this.highlight) return highlightClass(this.user)
},
style () {
if (this.highlight) {
const {
backgroundColor,
backgroundPosition,
backgroundImage,
...rest
} = highlightStyle(this.highlight)
return rest
}
},
classnames () {
return [
{
'-you': this.isYou,
'-highlighted': this.highlight
},
this.highlightType
]
},
...mapGetters(['mergedConfig']),
...mapState({
currentUser: state => state.users.currentUser
})
}
}
export default MentionLink
@@ -0,0 +1,91 @@
.MentionLink {
position: relative;
white-space: normal;
display: inline-block;
color: var(--link);
& .new,
& .original {
display: inline-block;
border-radius: 2px;
}
.full {
position: absolute;
display: inline-block;
pointer-events: none;
opacity: 0;
top: 100%;
left: 0;
height: 100%;
word-wrap: normal;
white-space: nowrap;
transition: opacity 0.2s ease;
z-index: 1;
margin-top: 0.25em;
padding: 0.5em;
user-select: all;
}
.short {
user-select: none;
}
& .short,
& .full {
white-space: nowrap;
}
.new {
&.-you {
& .shortName,
& .full {
font-weight: 600;
}
}
.at {
color: var(--link);
opacity: 0.8;
display: inline-block;
height: 50%;
line-height: 1;
padding: 0 0.1em;
vertical-align: -25%;
margin: 0;
}
&.-striped {
& .userName,
& .full {
background-image:
repeating-linear-gradient(
135deg,
var(--____highlight-tintColor),
var(--____highlight-tintColor) 5px,
var(--____highlight-tintColor2) 5px,
var(--____highlight-tintColor2) 10px
);
}
}
&.-solid {
& .userName,
& .full {
background-image: linear-gradient(var(--____highlight-tintColor2), var(--____highlight-tintColor2));
}
}
&.-side {
& .userName,
& .userNameFull {
box-shadow: 0 -5px 3px -4px inset var(--____highlight-solidColor);
}
}
}
&:hover .new .full {
opacity: 1;
pointer-events: initial;
}
}
@@ -0,0 +1,56 @@
<template>
<span
class="MentionLink"
>
<!-- eslint-disable vue/no-v-html -->
<a
v-if="!user"
:href="url"
class="original"
target="_blank"
v-html="content"
/>
<!-- eslint-enable vue/no-v-html -->
<span
v-if="user"
class="new"
:style="style"
:class="classnames"
>
<a
class="short button-unstyled"
:href="url"
@click.prevent="onClick"
>
<!-- eslint-disable vue/no-v-html -->
<FAIcon
size="sm"
icon="at"
class="at"
/><span class="shortName"><span
class="userName"
v-html="userName"
/></span>
<span
v-if="isYou"
class="you"
>{{ $t('status.you') }}</span>
<!-- eslint-enable vue/no-v-html -->
</a>
<span
v-if="userName !== userNameFull"
class="full popover-default"
:class="[highlightType]"
>
<span
class="userNameFull"
v-text="'@' + userNameFull"
/>
</span>
</span>
</span>
</template>
<script src="./mention_link.js"/>
<style lang="scss" src="./mention_link.scss"/>
@@ -0,0 +1,37 @@
import MentionLink from 'src/components/mention_link/mention_link.vue'
import { mapGetters } from 'vuex'
export const MENTIONS_LIMIT = 5
const MentionsLine = {
name: 'MentionsLine',
props: {
mentions: {
required: true,
type: Array
}
},
data: () => ({ expanded: false }),
components: {
MentionLink
},
computed: {
mentionsComputed () {
return this.mentions.slice(0, MENTIONS_LIMIT)
},
extraMentions () {
return this.mentions.slice(MENTIONS_LIMIT)
},
manyMentions () {
return this.extraMentions.length > 0
},
...mapGetters(['mergedConfig'])
},
methods: {
toggleShowMore () {
this.expanded = !this.expanded
}
}
}
export default MentionsLine
@@ -0,0 +1,11 @@
.MentionsLine {
.showMoreLess {
white-space: normal;
color: var(--link);
}
.fullExtraMentions,
.mention-link:not(:last-child) {
margin-right: 0.25em;
}
}
@@ -0,0 +1,43 @@
<template>
<span class="MentionsLine">
<MentionLink
v-for="mention in mentionsComputed"
:key="mention.index"
class="mention-link"
:content="mention.content"
:url="mention.url"
:first-mention="false"
/><span
v-if="manyMentions"
class="extraMentions"
>
<span
v-if="expanded"
class="fullExtraMentions"
>
<MentionLink
v-for="mention in extraMentions"
:key="mention.index"
class="mention-link"
:content="mention.content"
:url="mention.url"
:first-mention="false"
/>
</span><button
v-if="!expanded"
class="button-unstyled showMoreLess"
@click="toggleShowMore"
>
{{ $t('status.plus_more', { number: extraMentions.length }) }}
</button><button
v-if="expanded"
class="button-unstyled showMoreLess"
@click="toggleShowMore"
>
{{ $t('general.show_less') }}
</button>
</span>
</span>
</template>
<script src="./mentions_line.js" ></script>
<style lang="scss" src="./mentions_line.scss" />
@@ -44,6 +44,9 @@ const MobilePostStatusButton = {
return this.autohideFloatingPostButton && (this.hidden || this.inputActive) return this.autohideFloatingPostButton && (this.hidden || this.inputActive)
}, },
isPersistent () {
return !!this.$store.getters.mergedConfig.showNewPostButton
},
autohideFloatingPostButton () { autohideFloatingPostButton () {
return !!this.$store.getters.mergedConfig.autohideFloatingPostButton return !!this.$store.getters.mergedConfig.autohideFloatingPostButton
} }
@@ -2,7 +2,7 @@
<div v-if="isLoggedIn"> <div v-if="isLoggedIn">
<button <button
class="button-default new-status-button" class="button-default new-status-button"
:class="{ 'hidden': isHidden }" :class="{ 'hidden': isHidden, 'always-show': isPersistent }"
@click="openPostForm" @click="openPostForm"
> >
<FAIcon icon="pen" /> <FAIcon icon="pen" />
@@ -47,7 +47,7 @@
} }
@media all and (min-width: 801px) { @media all and (min-width: 801px) {
.new-status-button { .new-status-button:not(.always-show) {
display: none; display: none;
} }
} }
@@ -1,6 +1,11 @@
import { library } from '@fortawesome/fontawesome-svg-core'
import { faChevronDown } from '@fortawesome/free-solid-svg-icons'
import DialogModal from '../dialog_modal/dialog_modal.vue' import DialogModal from '../dialog_modal/dialog_modal.vue'
import Popover from '../popover/popover.vue' import Popover from '../popover/popover.vue'
library.add(faChevronDown)
const FORCE_NSFW = 'mrf_tag:media-force-nsfw' const FORCE_NSFW = 'mrf_tag:media-force-nsfw'
const STRIP_MEDIA = 'mrf_tag:media-strip' const STRIP_MEDIA = 'mrf_tag:media-strip'
const FORCE_UNLISTED = 'mrf_tag:force-unlisted' const FORCE_UNLISTED = 'mrf_tag:force-unlisted'
@@ -8,7 +8,7 @@
@show="setToggled(true)" @show="setToggled(true)"
@close="setToggled(false)" @close="setToggled(false)"
> >
<div slot="content"> <template v-slot:content>
<div class="dropdown-menu"> <div class="dropdown-menu">
<span v-if="user.is_local"> <span v-if="user.is_local">
<button <button
@@ -50,96 +50,98 @@
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.FORCE_NSFW)" @click="toggleTag(tags.FORCE_NSFW)"
> >
{{ $t('user_card.admin_menu.force_nsfw') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_NSFW) }" :class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_NSFW) }"
/> />
{{ $t('user_card.admin_menu.force_nsfw') }}
</button> </button>
<button <button
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.STRIP_MEDIA)" @click="toggleTag(tags.STRIP_MEDIA)"
> >
{{ $t('user_card.admin_menu.strip_media') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.STRIP_MEDIA) }" :class="{ 'menu-checkbox-checked': hasTag(tags.STRIP_MEDIA) }"
/> />
{{ $t('user_card.admin_menu.strip_media') }}
</button> </button>
<button <button
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.FORCE_UNLISTED)" @click="toggleTag(tags.FORCE_UNLISTED)"
> >
{{ $t('user_card.admin_menu.force_unlisted') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_UNLISTED) }" :class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_UNLISTED) }"
/> />
{{ $t('user_card.admin_menu.force_unlisted') }}
</button> </button>
<button <button
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.SANDBOX)" @click="toggleTag(tags.SANDBOX)"
> >
{{ $t('user_card.admin_menu.sandbox') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.SANDBOX) }" :class="{ 'menu-checkbox-checked': hasTag(tags.SANDBOX) }"
/> />
{{ $t('user_card.admin_menu.sandbox') }}
</button> </button>
<button <button
v-if="user.is_local" v-if="user.is_local"
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.DISABLE_REMOTE_SUBSCRIPTION)" @click="toggleTag(tags.DISABLE_REMOTE_SUBSCRIPTION)"
> >
{{ $t('user_card.admin_menu.disable_remote_subscription') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_REMOTE_SUBSCRIPTION) }" :class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_REMOTE_SUBSCRIPTION) }"
/> />
{{ $t('user_card.admin_menu.disable_remote_subscription') }}
</button> </button>
<button <button
v-if="user.is_local" v-if="user.is_local"
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.DISABLE_ANY_SUBSCRIPTION)" @click="toggleTag(tags.DISABLE_ANY_SUBSCRIPTION)"
> >
{{ $t('user_card.admin_menu.disable_any_subscription') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_ANY_SUBSCRIPTION) }" :class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_ANY_SUBSCRIPTION) }"
/> />
{{ $t('user_card.admin_menu.disable_any_subscription') }}
</button> </button>
<button <button
v-if="user.is_local" v-if="user.is_local"
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.QUARANTINE)" @click="toggleTag(tags.QUARANTINE)"
> >
{{ $t('user_card.admin_menu.quarantine') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.QUARANTINE) }" :class="{ 'menu-checkbox-checked': hasTag(tags.QUARANTINE) }"
/> />
{{ $t('user_card.admin_menu.quarantine') }}
</button> </button>
</span> </span>
</div> </div>
</div> </template>
<template v-slot:trigger>
<button <button
slot="trigger" class="btn button-default btn-block moderation-tools-button"
class="btn button-default btn-block"
:class="{ toggled }" :class="{ toggled }"
> >
{{ $t('user_card.admin_menu.moderation') }} {{ $t('user_card.admin_menu.moderation') }}
<FAIcon icon="chevron-down" />
</button> </button>
</template>
</Popover> </Popover>
<portal to="modal"> <portal to="modal">
<DialogModal <DialogModal
v-if="showDeleteUserDialog" v-if="showDeleteUserDialog"
:on-cancel="deleteUserDialog.bind(this, false)" :on-cancel="deleteUserDialog.bind(this, false)"
> >
<template slot="header"> <template v-slot:header>
{{ $t('user_card.admin_menu.delete_user') }} {{ $t('user_card.admin_menu.delete_user') }}
</template> </template>
<p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p> <p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
<template slot="footer"> <template v-slot:footer>
<button <button
class="btn button-default" class="btn button-default"
@click="deleteUserDialog(false)" @click="deleteUserDialog(false)"
@@ -163,25 +165,6 @@
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
.menu-checkbox {
float: right;
min-width: 22px;
max-width: 22px;
min-height: 22px;
max-height: 22px;
line-height: 22px;
text-align: center;
border-radius: 0px;
background-color: $fallback--fg;
background-color: var(--input, $fallback--fg);
box-shadow: 0px 0px 2px black inset;
box-shadow: var(--inputShadow);
&.menu-checkbox-checked::after {
content: '✓';
}
}
.moderation-tools-popover { .moderation-tools-popover {
height: 100%; height: 100%;
.trigger { .trigger {
@@ -189,4 +172,10 @@
height: 100%; height: 100%;
} }
} }
.moderation-tools-button {
svg,i {
font-size: 0.8em;
}
}
</style> </style>
@@ -1,17 +1,56 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { get } from 'lodash' import { get } from 'lodash'
/**
* This is for backwards compatibility. We originally didn't recieve
* extra info like a reason why an instance was rejected/quarantined/etc.
* Because we didn't want to break backwards compatibility it was decided
* to add an extra "info" key.
*/
const toInstanceReasonObject = (instances, info, key) => {
return instances.map(instance => {
if (info[key] && info[key][instance] && info[key][instance]['reason']) {
return { instance: instance, reason: info[key][instance]['reason'] }
}
return { instance: instance, reason: '' }
})
}
const MRFTransparencyPanel = { const MRFTransparencyPanel = {
computed: { computed: {
...mapState({ ...mapState({
federationPolicy: state => get(state, 'instance.federationPolicy'), federationPolicy: state => get(state, 'instance.federationPolicy'),
mrfPolicies: state => get(state, 'instance.federationPolicy.mrf_policies', []), mrfPolicies: state => get(state, 'instance.federationPolicy.mrf_policies', []),
quarantineInstances: state => get(state, 'instance.federationPolicy.quarantined_instances', []), quarantineInstances: state => toInstanceReasonObject(
acceptInstances: state => get(state, 'instance.federationPolicy.mrf_simple.accept', []), get(state, 'instance.federationPolicy.quarantined_instances', []),
rejectInstances: state => get(state, 'instance.federationPolicy.mrf_simple.reject', []), get(state, 'instance.federationPolicy.quarantined_instances_info', []),
ftlRemovalInstances: state => get(state, 'instance.federationPolicy.mrf_simple.federated_timeline_removal', []), 'quarantined_instances'
mediaNsfwInstances: state => get(state, 'instance.federationPolicy.mrf_simple.media_nsfw', []), ),
mediaRemovalInstances: state => get(state, 'instance.federationPolicy.mrf_simple.media_removal', []), acceptInstances: state => toInstanceReasonObject(
get(state, 'instance.federationPolicy.mrf_simple.accept', []),
get(state, 'instance.federationPolicy.mrf_simple_info', []),
'accept'
),
rejectInstances: state => toInstanceReasonObject(
get(state, 'instance.federationPolicy.mrf_simple.reject', []),
get(state, 'instance.federationPolicy.mrf_simple_info', []),
'reject'
),
ftlRemovalInstances: state => toInstanceReasonObject(
get(state, 'instance.federationPolicy.mrf_simple.federated_timeline_removal', []),
get(state, 'instance.federationPolicy.mrf_simple_info', []),
'federated_timeline_removal'
),
mediaNsfwInstances: state => toInstanceReasonObject(
get(state, 'instance.federationPolicy.mrf_simple.media_nsfw', []),
get(state, 'instance.federationPolicy.mrf_simple_info', []),
'media_nsfw'
),
mediaRemovalInstances: state => toInstanceReasonObject(
get(state, 'instance.federationPolicy.mrf_simple.media_removal', []),
get(state, 'instance.federationPolicy.mrf_simple_info', []),
'media_removal'
),
keywordsFtlRemoval: state => get(state, 'instance.federationPolicy.mrf_keyword.federated_timeline_removal', []), keywordsFtlRemoval: state => get(state, 'instance.federationPolicy.mrf_keyword.federated_timeline_removal', []),
keywordsReject: state => get(state, 'instance.federationPolicy.mrf_keyword.reject', []), keywordsReject: state => get(state, 'instance.federationPolicy.mrf_keyword.reject', []),
keywordsReplace: state => get(state, 'instance.federationPolicy.mrf_keyword.replace', []) keywordsReplace: state => get(state, 'instance.federationPolicy.mrf_keyword.replace', [])
@@ -0,0 +1,21 @@
.mrf-section {
margin: 1em;
table {
width:100%;
text-align: left;
padding-left:10px;
padding-bottom:20px;
th, td {
width: 180px;
max-width: 360px;
overflow: hidden;
vertical-align: text-top;
}
th+th, td+td {
width: auto;
}
}
}
@@ -31,13 +31,24 @@
<p>{{ $t("about.mrf.simple.accept_desc") }}</p> <p>{{ $t("about.mrf.simple.accept_desc") }}</p>
<ul> <table>
<li <tr>
v-for="instance in acceptInstances" <th>{{ $t("about.mrf.simple.instance") }}</th>
:key="instance" <th>{{ $t("about.mrf.simple.reason") }}</th>
v-text="instance" </tr>
/> <tr
</ul> v-for="entry in acceptInstances"
:key="entry.instance + '_accept'"
>
<td>{{ entry.instance }}</td>
<td v-if="entry.reason === ''">
{{ $t("about.mrf.simple.not_applicable") }}
</td>
<td v-else>
{{ entry.reason }}
</td>
</tr>
</table>
</div> </div>
<div v-if="rejectInstances.length"> <div v-if="rejectInstances.length">
@@ -45,13 +56,24 @@
<p>{{ $t("about.mrf.simple.reject_desc") }}</p> <p>{{ $t("about.mrf.simple.reject_desc") }}</p>
<ul> <table>
<li <tr>
v-for="instance in rejectInstances" <th>{{ $t("about.mrf.simple.instance") }}</th>
:key="instance" <th>{{ $t("about.mrf.simple.reason") }}</th>
v-text="instance" </tr>
/> <tr
</ul> v-for="entry in rejectInstances"
:key="entry.instance + '_reject'"
>
<td>{{ entry.instance }}</td>
<td v-if="entry.reason === ''">
{{ $t("about.mrf.simple.not_applicable") }}
</td>
<td v-else>
{{ entry.reason }}
</td>
</tr>
</table>
</div> </div>
<div v-if="quarantineInstances.length"> <div v-if="quarantineInstances.length">
@@ -59,13 +81,24 @@
<p>{{ $t("about.mrf.simple.quarantine_desc") }}</p> <p>{{ $t("about.mrf.simple.quarantine_desc") }}</p>
<ul> <table>
<li <tr>
v-for="instance in quarantineInstances" <th>{{ $t("about.mrf.simple.instance") }}</th>
:key="instance" <th>{{ $t("about.mrf.simple.reason") }}</th>
v-text="instance" </tr>
/> <tr
</ul> v-for="entry in quarantineInstances"
:key="entry.instance + '_quarantine'"
>
<td>{{ entry.instance }}</td>
<td v-if="entry.reason === ''">
{{ $t("about.mrf.simple.not_applicable") }}
</td>
<td v-else>
{{ entry.reason }}
</td>
</tr>
</table>
</div> </div>
<div v-if="ftlRemovalInstances.length"> <div v-if="ftlRemovalInstances.length">
@@ -73,13 +106,24 @@
<p>{{ $t("about.mrf.simple.ftl_removal_desc") }}</p> <p>{{ $t("about.mrf.simple.ftl_removal_desc") }}</p>
<ul> <table>
<li <tr>
v-for="instance in ftlRemovalInstances" <th>{{ $t("about.mrf.simple.instance") }}</th>
:key="instance" <th>{{ $t("about.mrf.simple.reason") }}</th>
v-text="instance" </tr>
/> <tr
</ul> v-for="entry in ftlRemovalInstances"
:key="entry.instance + '_ftl_removal'"
>
<td>{{ entry.instance }}</td>
<td v-if="entry.reason === ''">
{{ $t("about.mrf.simple.not_applicable") }}
</td>
<td v-else>
{{ entry.reason }}
</td>
</tr>
</table>
</div> </div>
<div v-if="mediaNsfwInstances.length"> <div v-if="mediaNsfwInstances.length">
@@ -87,13 +131,24 @@
<p>{{ $t("about.mrf.simple.media_nsfw_desc") }}</p> <p>{{ $t("about.mrf.simple.media_nsfw_desc") }}</p>
<ul> <table>
<li <tr>
v-for="instance in mediaNsfwInstances" <th>{{ $t("about.mrf.simple.instance") }}</th>
:key="instance" <th>{{ $t("about.mrf.simple.reason") }}</th>
v-text="instance" </tr>
/> <tr
</ul> v-for="entry in mediaNsfwInstances"
:key="entry.instance + '_media_nsfw'"
>
<td>{{ entry.instance }}</td>
<td v-if="entry.reason === ''">
{{ $t("about.mrf.simple.not_applicable") }}
</td>
<td v-else>
{{ entry.reason }}
</td>
</tr>
</table>
</div> </div>
<div v-if="mediaRemovalInstances.length"> <div v-if="mediaRemovalInstances.length">
@@ -101,13 +156,24 @@
<p>{{ $t("about.mrf.simple.media_removal_desc") }}</p> <p>{{ $t("about.mrf.simple.media_removal_desc") }}</p>
<ul> <table>
<li <tr>
v-for="instance in mediaRemovalInstances" <th>{{ $t("about.mrf.simple.instance") }}</th>
:key="instance" <th>{{ $t("about.mrf.simple.reason") }}</th>
v-text="instance" </tr>
/> <tr
</ul> v-for="entry in mediaRemovalInstances"
:key="entry.instance + '_media_removal'"
>
<td>{{ entry.instance }}</td>
<td v-if="entry.reason === ''">
{{ $t("about.mrf.simple.not_applicable") }}
</td>
<td v-else>
{{ entry.reason }}
</td>
</tr>
</table>
</div> </div>
<h2 v-if="hasKeywordPolicies"> <h2 v-if="hasKeywordPolicies">
@@ -161,7 +227,6 @@
<script src="./mrf_transparency_panel.js"></script> <script src="./mrf_transparency_panel.js"></script>
<style lang="scss"> <style lang="scss">
.mrf-section { @import '../../_variables.scss';
margin: 1em; @import './mrf_transparency_panel.scss';
}
</style> </style>
+20 -12
View File
@@ -1,4 +1,4 @@
import { timelineNames } from '../timeline_menu/timeline_menu.js' import TimelineMenuContent from '../timeline_menu/timeline_menu_content.vue'
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@@ -7,10 +7,12 @@ import {
faGlobe, faGlobe,
faBookmark, faBookmark,
faEnvelope, faEnvelope,
faHome, faChevronDown,
faChevronUp,
faComments, faComments,
faBell, faBell,
faInfoCircle faInfoCircle,
faStream
} from '@fortawesome/free-solid-svg-icons' } from '@fortawesome/free-solid-svg-icons'
library.add( library.add(
@@ -18,10 +20,12 @@ library.add(
faGlobe, faGlobe,
faBookmark, faBookmark,
faEnvelope, faEnvelope,
faHome, faChevronDown,
faChevronUp,
faComments, faComments,
faBell, faBell,
faInfoCircle faInfoCircle,
faStream
) )
const NavPanel = { const NavPanel = {
@@ -30,16 +34,20 @@ const NavPanel = {
this.$store.dispatch('startFetchingFollowRequests') this.$store.dispatch('startFetchingFollowRequests')
} }
}, },
computed: { components: {
onTimelineRoute () { TimelineMenuContent
return !!timelineNames()[this.$route.name]
}, },
timelinesRoute () { data () {
if (this.$store.state.interface.lastTimeline) { return {
return this.$store.state.interface.lastTimeline showTimelines: false
} }
return this.currentUser ? 'friends' : 'public-timeline'
}, },
methods: {
toggleTimelines () {
this.showTimelines = !this.showTimelines
}
},
computed: {
...mapState({ ...mapState({
currentUser: state => state.users.currentUser, currentUser: state => state.users.currentUser,
followRequestCount: state => state.api.followRequests.length, followRequestCount: state => state.api.followRequests.length,
+57 -13
View File
@@ -3,19 +3,33 @@
<div class="panel panel-default"> <div class="panel panel-default">
<ul> <ul>
<li v-if="currentUser || !privateMode"> <li v-if="currentUser || !privateMode">
<router-link <button
:to="{ name: timelinesRoute }" class="button-unstyled menu-item"
:class="onTimelineRoute && 'router-link-active'" @click="toggleTimelines"
> >
<FAIcon <FAIcon
fixed-width fixed-width
class="fa-scale-110" class="fa-scale-110"
icon="home" icon="stream"
/>{{ $t("nav.timelines") }} />{{ $t("nav.timelines") }}
</router-link> <FAIcon
class="timelines-chevron"
fixed-width
:icon="showTimelines ? 'chevron-up' : 'chevron-down'"
/>
</button>
<div
v-show="showTimelines"
class="timelines-background"
>
<TimelineMenuContent class="timelines" />
</div>
</li> </li>
<li v-if="currentUser"> <li v-if="currentUser">
<router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }"> <router-link
class="menu-item"
:to="{ name: 'interactions', params: { username: currentUser.screen_name } }"
>
<FAIcon <FAIcon
fixed-width fixed-width
class="fa-scale-110" class="fa-scale-110"
@@ -24,7 +38,10 @@
</router-link> </router-link>
</li> </li>
<li v-if="currentUser && pleromaChatMessagesAvailable"> <li v-if="currentUser && pleromaChatMessagesAvailable">
<router-link :to="{ name: 'chats', params: { username: currentUser.screen_name } }"> <router-link
class="menu-item"
:to="{ name: 'chats', params: { username: currentUser.screen_name } }"
>
<div <div
v-if="unreadChatCount" v-if="unreadChatCount"
class="badge badge-notification" class="badge badge-notification"
@@ -39,7 +56,10 @@
</router-link> </router-link>
</li> </li>
<li v-if="currentUser && currentUser.locked"> <li v-if="currentUser && currentUser.locked">
<router-link :to="{ name: 'friend-requests' }"> <router-link
class="menu-item"
:to="{ name: 'friend-requests' }"
>
<FAIcon <FAIcon
fixed-width fixed-width
class="fa-scale-110" class="fa-scale-110"
@@ -54,7 +74,10 @@
</router-link> </router-link>
</li> </li>
<li> <li>
<router-link :to="{ name: 'about' }"> <router-link
class="menu-item"
:to="{ name: 'about' }"
>
<FAIcon <FAIcon
fixed-width fixed-width
class="fa-scale-110" class="fa-scale-110"
@@ -91,14 +114,14 @@
border-color: var(--border, $fallback--border); border-color: var(--border, $fallback--border);
padding: 0; padding: 0;
&:first-child a { &:first-child .menu-item {
border-top-right-radius: $fallback--panelRadius; border-top-right-radius: $fallback--panelRadius;
border-top-right-radius: var(--panelRadius, $fallback--panelRadius); border-top-right-radius: var(--panelRadius, $fallback--panelRadius);
border-top-left-radius: $fallback--panelRadius; border-top-left-radius: $fallback--panelRadius;
border-top-left-radius: var(--panelRadius, $fallback--panelRadius); border-top-left-radius: var(--panelRadius, $fallback--panelRadius);
} }
&:last-child a { &:last-child .menu-item {
border-bottom-right-radius: $fallback--panelRadius; border-bottom-right-radius: $fallback--panelRadius;
border-bottom-right-radius: var(--panelRadius, $fallback--panelRadius); border-bottom-right-radius: var(--panelRadius, $fallback--panelRadius);
border-bottom-left-radius: $fallback--panelRadius; border-bottom-left-radius: $fallback--panelRadius;
@@ -110,13 +133,15 @@
border: none; border: none;
} }
a { .menu-item {
display: block; display: block;
box-sizing: border-box; box-sizing: border-box;
align-items: stretch;
height: 3.5em; height: 3.5em;
line-height: 3.5em; line-height: 3.5em;
padding: 0 1em; padding: 0 1em;
width: 100%;
color: $fallback--link;
color: var(--link, $fallback--link);
&:hover { &:hover {
background-color: $fallback--lightBg; background-color: $fallback--lightBg;
@@ -146,6 +171,25 @@
} }
} }
.timelines-chevron {
margin-left: 0.8em;
font-size: 1.1em;
}
.timelines-background {
padding: 0 0 0 0.6em;
background-color: $fallback--lightBg;
background-color: var(--selectedMenu, $fallback--lightBg);
border-top: 1px solid;
border-color: $fallback--border;
border-color: var(--border, $fallback--border);
}
.timelines {
background-color: $fallback--bg;
background-color: var(--bg, $fallback--bg);
}
.fa-scale-110 { .fa-scale-110 {
margin-right: 0.8em; margin-right: 0.8em;
} }
+3 -1
View File
@@ -4,6 +4,7 @@ import Status from '../status/status.vue'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
import UserCard from '../user_card/user_card.vue' import UserCard from '../user_card/user_card.vue'
import Timeago from '../timeago/timeago.vue' import Timeago from '../timeago/timeago.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
import { isStatusNotification } from '../../services/notification_utils/notification_utils.js' import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
@@ -44,7 +45,8 @@ const Notification = {
UserAvatar, UserAvatar,
UserCard, UserCard,
Timeago, Timeago,
Status Status,
RichContent
}, },
methods: { methods: {
toggleUserExpanded () { toggleUserExpanded () {
@@ -2,6 +2,8 @@
// TODO Copypaste from Status, should unify it somehow // TODO Copypaste from Status, should unify it somehow
.Notification { .Notification {
--emoji-size: 14px;
&.-muted { &.-muted {
padding: 0.25em 0.6em; padding: 0.25em 0.6em;
height: 1.2em; height: 1.2em;
+5 -3
View File
@@ -51,12 +51,14 @@
<span class="notification-details"> <span class="notification-details">
<div class="name-and-action"> <div class="name-and-action">
<!-- eslint-disable vue/no-v-html --> <!-- eslint-disable vue/no-v-html -->
<bdi <bdi v-if="!!notification.from_profile.name_html">
v-if="!!notification.from_profile.name_html" <RichContent
class="username" class="username"
:title="'@'+notification.from_profile.screen_name_ui" :title="'@'+notification.from_profile.screen_name_ui"
v-html="notification.from_profile.name_html" :html="notification.from_profile.name_html"
:emoji="notification.from_profile.emoji"
/> />
</bdi>
<!-- eslint-enable vue/no-v-html --> <!-- eslint-enable vue/no-v-html -->
<span <span
v-else v-else
@@ -0,0 +1,122 @@
<template>
<Popover
trigger="click"
class="NotificationFilters"
placement="bottom"
:bound-to="{ x: 'container' }"
>
<template v-slot:content>
<div class="dropdown-menu">
<button
class="button-default dropdown-item"
@click="toggleNotificationFilter('likes')"
>
<span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': filters.likes }"
/>{{ $t('settings.notification_visibility_likes') }}
</button>
<button
class="button-default dropdown-item"
@click="toggleNotificationFilter('repeats')"
>
<span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': filters.repeats }"
/>{{ $t('settings.notification_visibility_repeats') }}
</button>
<button
class="button-default dropdown-item"
@click="toggleNotificationFilter('follows')"
>
<span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': filters.follows }"
/>{{ $t('settings.notification_visibility_follows') }}
</button>
<button
class="button-default dropdown-item"
@click="toggleNotificationFilter('mentions')"
>
<span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': filters.mentions }"
/>{{ $t('settings.notification_visibility_mentions') }}
</button>
<button
class="button-default dropdown-item"
@click="toggleNotificationFilter('emojiReactions')"
>
<span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': filters.emojiReactions }"
/>{{ $t('settings.notification_visibility_emoji_reactions') }}
</button>
<button
class="button-default dropdown-item"
@click="toggleNotificationFilter('moves')"
>
<span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': filters.moves }"
/>{{ $t('settings.notification_visibility_moves') }}
</button>
</div>
</template>
<template v-slot:trigger>
<button class="button-unstyled">
<FAIcon icon="filter" />
</button>
</template>
</Popover>
</template>
<script>
import Popover from '../popover/popover.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faFilter } from '@fortawesome/free-solid-svg-icons'
library.add(
faFilter
)
export default {
components: { Popover },
computed: {
filters () {
return this.$store.getters.mergedConfig.notificationVisibility
}
},
methods: {
toggleNotificationFilter (type) {
this.$store.dispatch('setOption', {
name: 'notificationVisibility',
value: {
...this.filters,
[type]: !this.filters[type]
}
})
}
}
}
</script>
<style lang="scss">
.NotificationFilters {
align-self: stretch;
> button {
font-size: 1.2em;
padding-left: 0.7em;
padding-right: 0.2em;
line-height: 100%;
height: 100%;
}
.dropdown-item {
margin: 0;
}
}
</style>
@@ -1,5 +1,6 @@
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import Notification from '../notification/notification.vue' import Notification from '../notification/notification.vue'
import NotificationFilters from './notification_filters.vue'
import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js' import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js'
import { import {
notificationsFromStore, notificationsFromStore,
@@ -17,6 +18,10 @@ library.add(
const DEFAULT_SEEN_TO_DISPLAY_COUNT = 30 const DEFAULT_SEEN_TO_DISPLAY_COUNT = 30
const Notifications = { const Notifications = {
components: {
Notification,
NotificationFilters
},
props: { props: {
// Disables display of panel header // Disables display of panel header
noHeading: Boolean, noHeading: Boolean,
@@ -35,11 +40,6 @@ const Notifications = {
seenToDisplayCount: DEFAULT_SEEN_TO_DISPLAY_COUNT seenToDisplayCount: DEFAULT_SEEN_TO_DISPLAY_COUNT
} }
}, },
created () {
const store = this.$store
const credentials = store.state.users.currentUser.credentials
notificationsFetcher.fetchAndUpdate({ store, credentials })
},
computed: { computed: {
mainClass () { mainClass () {
return this.minimalMode ? '' : 'panel panel-default' return this.minimalMode ? '' : 'panel panel-default'
@@ -70,9 +70,6 @@ const Notifications = {
}, },
...mapGetters(['unreadChatCount']) ...mapGetters(['unreadChatCount'])
}, },
components: {
Notification
},
watch: { watch: {
unseenCountTitle (count) { unseenCountTitle (count) {
if (count > 0) { if (count > 0) {
@@ -1,6 +1,6 @@
@import '../../_variables.scss'; @import '../../_variables.scss';
.notifications { .Notifications {
&:not(.minimal) { &:not(.minimal) {
// a bit of a hack to allow scrolling below notifications // a bit of a hack to allow scrolling below notifications
padding-bottom: 15em; padding-bottom: 15em;
@@ -11,6 +11,10 @@
color: var(--text, $fallback--text); color: var(--text, $fallback--text);
} }
.notifications-footer {
border: none;
}
.notification { .notification {
position: relative; position: relative;
@@ -82,7 +86,6 @@
} }
} }
.follow-text, .move-text { .follow-text, .move-text {
padding: 0.5em 0; padding: 0.5em 0;
overflow-wrap: break-word; overflow-wrap: break-word;
@@ -145,13 +148,6 @@
max-width: 100%; max-width: 100%;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
img {
width: 14px;
height: 14px;
vertical-align: middle;
object-fit: contain
}
} }
.timeago { .timeago {
@@ -1,7 +1,7 @@
<template> <template>
<div <div
:class="{ minimal: minimalMode }" :class="{ minimal: minimalMode }"
class="notifications" class="Notifications"
> >
<div :class="mainClass"> <div :class="mainClass">
<div <div
@@ -22,6 +22,7 @@
> >
{{ $t('notifications.read') }} {{ $t('notifications.read') }}
</button> </button>
<NotificationFilters />
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div <div
@@ -34,10 +35,10 @@
<notification :notification="notification" /> <notification :notification="notification" />
</div> </div>
</div> </div>
<div class="panel-footer"> <div class="panel-footer notifications-footer">
<div <div
v-if="bottomedOut" v-if="bottomedOut"
class="new-status-notification text-center panel-footer faint" class="new-status-notification text-center faint"
> >
{{ $t('notifications.no_more_notifications') }} {{ $t('notifications.no_more_notifications') }}
</div> </div>
@@ -46,13 +47,13 @@
class="button-unstyled -link -fullwidth" class="button-unstyled -link -fullwidth"
@click.prevent="fetchOlderNotifications()" @click.prevent="fetchOlderNotifications()"
> >
<div class="new-status-notification text-center panel-footer"> <div class="new-status-notification text-center">
{{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older') }} {{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older') }}
</div> </div>
</button> </button>
<div <div
v-else v-else
class="new-status-notification text-center panel-footer" class="new-status-notification text-center"
> >
<FAIcon <FAIcon
icon="circle-notch" icon="circle-notch"
@@ -53,7 +53,7 @@
type="submit" type="submit"
class="btn button-default btn-block" class="btn button-default btn-block"
> >
{{ $t('general.submit') }} {{ $t('settings.save') }}
</button> </button>
</div> </div>
</div> </div>
+7 -3
View File
@@ -1,10 +1,14 @@
import Timeago from '../timeago/timeago.vue' import Timeago from 'components/timeago/timeago.vue'
import RichContent from 'components/rich_content/rich_content.jsx'
import { forEach, map } from 'lodash' import { forEach, map } from 'lodash'
export default { export default {
name: 'Poll', name: 'Poll',
props: ['basePoll'], props: ['basePoll', 'emoji'],
components: { Timeago }, components: {
Timeago,
RichContent
},
data () { data () {
return { return {
loading: false, loading: false,
+10 -4
View File
@@ -17,8 +17,11 @@
<span class="result-percentage"> <span class="result-percentage">
{{ percentageForOption(option.votes_count) }}% {{ percentageForOption(option.votes_count) }}%
</span> </span>
<!-- eslint-disable-next-line vue/no-v-html --> <RichContent
<span v-html="option.title_html" /> :html="option.title_html"
:handle-links="false"
:emoji="emoji"
/>
</div> </div>
<div <div
class="result-fill" class="result-fill"
@@ -42,8 +45,11 @@
:value="index" :value="index"
> >
<label class="option-vote"> <label class="option-vote">
<!-- eslint-disable-next-line vue/no-v-html --> <RichContent
<div v-html="option.title_html" /> :html="option.title_html"
:handle-links="false"
:emoji="emoji"
/>
</label> </label>
</div> </div>
</div> </div>
+4 -2
View File
@@ -1,19 +1,21 @@
import * as DateUtils from 'src/services/date_utils/date_utils.js' import * as DateUtils from 'src/services/date_utils/date_utils.js'
import { uniq } from 'lodash' import { uniq } from 'lodash'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import Select from '../select/select.vue'
import { import {
faTimes, faTimes,
faChevronDown,
faPlus faPlus
} from '@fortawesome/free-solid-svg-icons' } from '@fortawesome/free-solid-svg-icons'
library.add( library.add(
faTimes, faTimes,
faChevronDown,
faPlus faPlus
) )
export default { export default {
components: {
Select
},
name: 'PollForm', name: 'PollForm',
props: ['visible'], props: ['visible'],
data: () => ({ data: () => ({
+16 -32
View File
@@ -46,23 +46,19 @@
class="poll-type" class="poll-type"
:title="$t('polls.type')" :title="$t('polls.type')"
> >
<label <Select
for="poll-type-selector"
class="select"
>
<select
v-model="pollType" v-model="pollType"
class="select" class="poll-type-select"
unstyled="true"
@change="updatePollToParent" @change="updatePollToParent"
> >
<option value="single">{{ $t('polls.single_choice') }}</option> <option value="single">
<option value="multiple">{{ $t('polls.multiple_choices') }}</option> {{ $t('polls.single_choice') }}
</select> </option>
<FAIcon <option value="multiple">
class="select-down-icon" {{ $t('polls.multiple_choices') }}
icon="chevron-down" </option>
/> </Select>
</label>
</div> </div>
<div <div
class="poll-expiry" class="poll-expiry"
@@ -76,9 +72,10 @@
:max="maxExpirationInCurrentUnit" :max="maxExpirationInCurrentUnit"
@change="expiryAmountChange" @change="expiryAmountChange"
> >
<label class="expiry-unit select"> <Select
<select
v-model="expiryUnit" v-model="expiryUnit"
unstyled="true"
class="expiry-unit"
@change="expiryAmountChange" @change="expiryAmountChange"
> >
<option <option
@@ -88,12 +85,7 @@
> >
{{ $t(`time.${unit}_short`, ['']) }} {{ $t(`time.${unit}_short`, ['']) }}
</option> </option>
</select> </Select>
<FAIcon
class="select-down-icon"
icon="chevron-down"
/>
</label>
</div> </div>
</div> </div>
</div> </div>
@@ -147,10 +139,8 @@
.poll-type { .poll-type {
margin-right: 0.75em; margin-right: 0.75em;
flex: 1 1 60%; flex: 1 1 60%;
.select {
border: none; .poll-type-select {
box-shadow: none;
background-color: transparent;
padding-right: 0.75em; padding-right: 0.75em;
} }
} }
@@ -162,12 +152,6 @@
width: 3em; width: 3em;
text-align: right; text-align: right;
} }
.expiry-unit {
border: none;
box-shadow: none;
background-color: transparent;
}
} }
} }
</style> </style>
+13 -3
View File
@@ -3,25 +3,32 @@ const Popover = {
props: { props: {
// Action to trigger popover: either 'hover' or 'click' // Action to trigger popover: either 'hover' or 'click'
trigger: String, trigger: String,
// Either 'top' or 'bottom' // Either 'top' or 'bottom'
placement: String, placement: String,
// Takes object with properties 'x' and 'y', values of these can be // Takes object with properties 'x' and 'y', values of these can be
// 'container' for using offsetParent as boundaries for either axis // 'container' for using offsetParent as boundaries for either axis
// or 'viewport' // or 'viewport'
boundTo: Object, boundTo: Object,
// Takes a selector to use as a replacement for the parent container // Takes a selector to use as a replacement for the parent container
// for getting boundaries for x an y axis // for getting boundaries for x an y axis
boundToSelector: String, boundToSelector: String,
// Takes a top/bottom/left/right object, how much space to leave // Takes a top/bottom/left/right object, how much space to leave
// between boundary and popover element // between boundary and popover element
margin: Object, margin: Object,
// Takes a x/y object and tells how many pixels to offset from // Takes a x/y object and tells how many pixels to offset from
// anchor point on either axis // anchor point on either axis
offset: Object, offset: Object,
// Replaces the classes you may want for the popover container. // Replaces the classes you may want for the popover container.
// Use 'popover-default' in addition to get the default popover // Use 'popover-default' in addition to get the default popover
// styles with your custom class. // styles with your custom class.
popoverClass: String, popoverClass: String,
// If true, subtract padding when calculating position for the popover, // If true, subtract padding when calculating position for the popover,
// use it when popover offset looks to be different on top vs bottom. // use it when popover offset looks to be different on top vs bottom.
removePadding: Boolean removePadding: Boolean
@@ -47,8 +54,11 @@ const Popover = {
} }
// Popover will be anchored around this element, trigger ref is the container, so // Popover will be anchored around this element, trigger ref is the container, so
// its children are what are inside the slot. Expect only one slot="trigger". // its children are what are inside the slot. Expect only one v-slot:trigger.
const anchorEl = (this.$refs.trigger && this.$refs.trigger.children[0]) || this.$el const anchorEl = (this.$refs.trigger && this.$refs.trigger.children[0]) || this.$el
// SVGs don't have offsetWidth/Height, use fallback
const anchorWidth = anchorEl.offsetWidth || anchorEl.clientWidth
const anchorHeight = anchorEl.offsetHeight || anchorEl.clientHeight
const screenBox = anchorEl.getBoundingClientRect() const screenBox = anchorEl.getBoundingClientRect()
// Screen position of the origin point for popover // Screen position of the origin point for popover
const origin = { x: screenBox.left + screenBox.width * 0.5, y: screenBox.top } const origin = { x: screenBox.left + screenBox.width * 0.5, y: screenBox.top }
@@ -107,11 +117,11 @@ const Popover = {
const yOffset = (this.offset && this.offset.y) || 0 const yOffset = (this.offset && this.offset.y) || 0
const translateY = usingTop const translateY = usingTop
? -anchorEl.offsetHeight + vPadding - yOffset - content.offsetHeight ? -anchorHeight + vPadding - yOffset - content.offsetHeight
: yOffset : yOffset
const xOffset = (this.offset && this.offset.x) || 0 const xOffset = (this.offset && this.offset.x) || 0
const translateX = (anchorEl.offsetWidth * 0.5) - content.offsetWidth * 0.5 + horizOffset + xOffset const translateX = anchorWidth * 0.5 - content.offsetWidth * 0.5 + horizOffset + xOffset
// Note, separate translateX and translateY avoids blurry text on chromium, // Note, separate translateX and translateY avoids blurry text on chromium,
// single translate or translate3d resulted in blurry text. // single translate or translate3d resulted in blurry text.
+30 -5
View File
@@ -82,10 +82,9 @@
.dropdown-item { .dropdown-item {
line-height: 21px; line-height: 21px;
margin-right: 5px;
overflow: auto; overflow: auto;
display: block; display: block;
padding: .25rem 1.0rem .25rem 1.5rem; padding: .5em 0.75em;
clear: both; clear: both;
font-weight: 400; font-weight: 400;
text-align: inherit; text-align: inherit;
@@ -101,10 +100,9 @@
--btnText: var(--popoverText, $fallback--text); --btnText: var(--popoverText, $fallback--text);
&-icon { &-icon {
padding-left: 0.5rem;
svg { svg {
margin-right: 0.25rem; width: 22px;
margin-right: 0.75rem;
color: var(--menuPopoverIcon, $fallback--icon) color: var(--menuPopoverIcon, $fallback--icon)
} }
} }
@@ -123,6 +121,33 @@
} }
} }
.menu-checkbox {
display: inline-block;
vertical-align: middle;
min-width: 22px;
max-width: 22px;
min-height: 22px;
max-height: 22px;
line-height: 22px;
text-align: center;
border-radius: 0px;
background-color: $fallback--fg;
background-color: var(--input, $fallback--fg);
box-shadow: 0px 0px 2px black inset;
box-shadow: var(--inputShadow);
margin-right: 0.75em;
&.menu-checkbox-checked::after {
font-size: 1.25em;
content: '✓';
}
&.menu-checkbox-radio::after {
font-size: 2em;
content: '•';
}
}
} }
} }
</style> </style>
@@ -11,10 +11,10 @@ import { reject, map, uniqBy, debounce } from 'lodash'
import suggestor from '../emoji_input/suggestor.js' import suggestor from '../emoji_input/suggestor.js'
import { mapGetters, mapState } from 'vuex' import { mapGetters, mapState } from 'vuex'
import Checkbox from '../checkbox/checkbox.vue' import Checkbox from '../checkbox/checkbox.vue'
import Select from '../select/select.vue'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
faChevronDown,
faSmileBeam, faSmileBeam,
faPollH, faPollH,
faUpload, faUpload,
@@ -24,7 +24,6 @@ import {
} from '@fortawesome/free-solid-svg-icons' } from '@fortawesome/free-solid-svg-icons'
library.add( library.add(
faChevronDown,
faSmileBeam, faSmileBeam,
faPollH, faPollH,
faUpload, faUpload,
@@ -84,6 +83,7 @@ const PostStatusForm = {
PollForm, PollForm,
ScopeSelector, ScopeSelector,
Checkbox, Checkbox,
Select,
Attachment, Attachment,
StatusContent StatusContent
}, },
@@ -115,7 +115,7 @@ const PostStatusForm = {
? this.copyMessageScope ? this.copyMessageScope
: this.$store.state.users.currentUser.default_scope : this.$store.state.users.currentUser.default_scope
const { postContentType: contentType } = this.$store.getters.mergedConfig const { postContentType: contentType, sensitiveByDefault } = this.$store.getters.mergedConfig
return { return {
dropFiles: [], dropFiles: [],
@@ -126,7 +126,7 @@ const PostStatusForm = {
newStatus: { newStatus: {
spoilerText: this.subject || '', spoilerText: this.subject || '',
status: statusText, status: statusText,
nsfw: false, nsfw: !!sensitiveByDefault,
files: [], files: [],
poll: {}, poll: {},
mediaDescriptions: {}, mediaDescriptions: {},
@@ -189,11 +189,7 @@
v-if="postFormats.length > 1" v-if="postFormats.length > 1"
class="text-format" class="text-format"
> >
<label <Select
for="post-content-type"
class="select"
>
<select
id="post-content-type" id="post-content-type"
v-model="newStatus.contentType" v-model="newStatus.contentType"
class="form-control" class="form-control"
@@ -205,12 +201,7 @@
> >
{{ $t(`post_status.content_type["${postFormat}"]`) }} {{ $t(`post_status.content_type["${postFormat}"]`) }}
</option> </option>
</select> </Select>
<FAIcon
class="select-down-icon"
icon="chevron-down"
/>
</label>
</div> </div>
<div <div
v-if="postFormats.length === 1 && postFormats[0] !== 'text/plain'" v-if="postFormats.length === 1 && postFormats[0] !== 'text/plain'"
@@ -272,7 +263,7 @@
disabled disabled
class="btn button-default" class="btn button-default"
> >
{{ $t('general.submit') }} {{ $t('post_status.post') }}
</button> </button>
<!-- touchstart is used to keep the OSK at the same position after a message send --> <!-- touchstart is used to keep the OSK at the same position after a message send -->
<button <button
@@ -282,7 +273,7 @@
@touchstart.stop.prevent="postStatus($event, newStatus)" @touchstart.stop.prevent="postStatus($event, newStatus)"
@click.stop.prevent="postStatus($event, newStatus)" @click.stop.prevent="postStatus($event, newStatus)"
> >
{{ $t('general.submit') }} {{ $t('post_status.post') }}
</button> </button>
</div> </div>
<div <div
+7 -9
View File
@@ -8,10 +8,7 @@
remove-padding remove-padding
@show="focusInput" @show="focusInput"
> >
<div <template v-slot:content="{close}">
slot="content"
slot-scope="{close}"
>
<div class="reaction-picker-filter"> <div class="reaction-picker-filter">
<input <input
v-model="filterWord" v-model="filterWord"
@@ -41,17 +38,18 @@
</span> </span>
<div class="reaction-bottom-fader" /> <div class="reaction-bottom-fader" />
</div> </div>
</div> </template>
<span <template v-slot:trigger>
slot="trigger" <button
class="popover-trigger" class="button-unstyled popover-trigger"
:title="$t('tool_tip.add_reaction')" :title="$t('tool_tip.add_reaction')"
> >
<FAIcon <FAIcon
class="fa-scale-110 fa-old-padding" class="fa-scale-110 fa-old-padding"
:icon="['far', 'smile-beam']" :icon="['far', 'smile-beam']"
/> />
</span> </button>
</template>
</Popover> </Popover>
</template> </template>
+1 -1
View File
@@ -230,7 +230,7 @@
type="submit" type="submit"
class="btn button-default" class="btn button-default"
> >
{{ $t('general.submit') }} {{ $t('registration.register') }}
</button> </button>
</div> </div>
</div> </div>
@@ -0,0 +1,327 @@
import Vue from 'vue'
import { unescape, flattenDeep } from 'lodash'
import { getTagName, processTextForEmoji, getAttrs } from 'src/services/html_converter/utility.service.js'
import { convertHtmlToTree } from 'src/services/html_converter/html_tree_converter.service.js'
import { convertHtmlToLines } from 'src/services/html_converter/html_line_converter.service.js'
import StillImage from 'src/components/still-image/still-image.vue'
import MentionsLine, { MENTIONS_LIMIT } from 'src/components/mentions_line/mentions_line.vue'
import HashtagLink from 'src/components/hashtag_link/hashtag_link.vue'
import './rich_content.scss'
/**
* RichContent, The Über-powered component for rendering Post HTML.
*
* This takes post HTML and does multiple things to it:
* - Groups all mentions into <MentionsLine>, this affects all mentions regardles
* of where they are (beginning/middle/end), even single mentions are converted
* to a <MentionsLine> containing single <MentionLink>.
* - Replaces emoji shortcodes with <StillImage>'d images.
*
* There are two problems with this component's architecture:
* 1. Parsing HTML and rendering are inseparable. Attempts to separate the two
* proven to be a massive overcomplication due to amount of things done here.
* 2. We need to output both render and some extra data, which seems to be imp-
* possible in vue. Current solution is to emit 'parseReady' event when parsing
* is done within render() function.
*
* Apart from that one small hiccup with emit in render this _should_ be vue3-ready
*/
export default Vue.component('RichContent', {
name: 'RichContent',
props: {
// Original html content
html: {
required: true,
type: String
},
attentions: {
required: false,
default: () => []
},
// Emoji object, as in status.emojis, note the "s" at the end...
emoji: {
required: true,
type: Array
},
// Whether to handle links or not (posts: yes, everything else: no)
handleLinks: {
required: false,
type: Boolean,
default: false
},
// Meme arrows
greentext: {
required: false,
type: Boolean,
default: false
}
},
// NEVER EVER TOUCH DATA INSIDE RENDER
render (h) {
// Pre-process HTML
const { newHtml: html } = preProcessPerLine(this.html, this.greentext)
let currentMentions = null // Current chain of mentions, we group all mentions together
// This is used to recover spacing removed when parsing mentions
let lastSpacing = ''
const lastTags = [] // Tags that appear at the end of post body
const writtenMentions = [] // All mentions that appear in post body
const invisibleMentions = [] // All mentions that go beyond the limiter (see MentionsLine)
// to collapse too many mentions in a row
const writtenTags = [] // All tags that appear in post body
// unique index for vue "tag" property
let mentionIndex = 0
let tagsIndex = 0
const renderImage = (tag) => {
return <StillImage
{...{ attrs: getAttrs(tag) }}
class="img"
/>
}
const renderHashtag = (attrs, children, encounteredTextReverse) => {
const linkData = getLinkData(attrs, children, tagsIndex++)
writtenTags.push(linkData)
if (!encounteredTextReverse) {
lastTags.push(linkData)
}
return <HashtagLink {...{ props: linkData }}/>
}
const renderMention = (attrs, children) => {
const linkData = getLinkData(attrs, children, mentionIndex++)
linkData.notifying = this.attentions.some(a => a.statusnet_profile_url === linkData.url)
writtenMentions.push(linkData)
if (currentMentions === null) {
currentMentions = []
}
currentMentions.push(linkData)
if (currentMentions.length > MENTIONS_LIMIT) {
invisibleMentions.push(linkData)
}
if (currentMentions.length === 1) {
return <MentionsLine mentions={ currentMentions } />
} else {
return ''
}
}
// Processor to use with html_tree_converter
const processItem = (item, index, array, what) => {
// Handle text nodes - just add emoji
if (typeof item === 'string') {
const emptyText = item.trim() === ''
if (item.includes('\n')) {
currentMentions = null
}
if (emptyText) {
// don't include spaces when processing mentions - we'll include them
// in MentionsLine
lastSpacing = item
return currentMentions !== null ? item.trim() : item
}
currentMentions = null
if (item.includes(':')) {
item = ['', processTextForEmoji(
item,
this.emoji,
({ shortcode, url }) => {
return <StillImage
class="emoji img"
src={url}
title={`:${shortcode}:`}
alt={`:${shortcode}:`}
/>
}
)]
}
return item
}
// Handle tag nodes
if (Array.isArray(item)) {
const [opener, children, closer] = item
const Tag = getTagName(opener)
const attrs = getAttrs(opener)
const previouslyMentions = currentMentions !== null
/* During grouping of mentions we trim all the empty text elements
* This padding is added to recover last space removed in case
* we have a tag right next to mentions
*/
const mentionsLinePadding =
// Padding is only needed if we just finished parsing mentions
previouslyMentions &&
// Don't add padding if content is string and has padding already
!(children && typeof children[0] === 'string' && children[0].match(/^\s/))
? lastSpacing
: ''
switch (Tag) {
case 'br':
currentMentions = null
break
case 'img': // replace images with StillImage
return ['', [mentionsLinePadding, renderImage(opener)], '']
case 'a': // replace mentions with MentionLink
if (!this.handleLinks) break
if (attrs['class'] && attrs['class'].includes('mention')) {
// Handling mentions here
return renderMention(attrs, children)
} else {
currentMentions = null
break
}
case 'span':
if (this.handleLinks && attrs['class'] && attrs['class'].includes('h-card')) {
return ['', children.map(processItem), '']
}
}
if (children !== undefined) {
return [
'',
[
mentionsLinePadding,
[opener, children.map(processItem), closer]
],
''
]
} else {
return ['', [mentionsLinePadding, item], '']
}
}
}
// Processor for back direction (for finding "last" stuff, just easier this way)
let encounteredTextReverse = false
const processItemReverse = (item, index, array, what) => {
// Handle text nodes - just add emoji
if (typeof item === 'string') {
const emptyText = item.trim() === ''
if (emptyText) return item
if (!encounteredTextReverse) encounteredTextReverse = true
return unescape(item)
} else if (Array.isArray(item)) {
// Handle tag nodes
const [opener, children] = item
const Tag = opener === '' ? '' : getTagName(opener)
switch (Tag) {
case 'a': // replace mentions with MentionLink
if (!this.handleLinks) break
const attrs = getAttrs(opener)
// should only be this
if (
(attrs['class'] && attrs['class'].includes('hashtag')) || // Pleroma style
(attrs['rel'] === 'tag') // Mastodon style
) {
return renderHashtag(attrs, children, encounteredTextReverse)
} else {
attrs.target = '_blank'
const newChildren = [...children].reverse().map(processItemReverse).reverse()
return <a {...{ attrs }}>
{ newChildren }
</a>
}
case '':
return [...children].reverse().map(processItemReverse).reverse()
}
// Render tag as is
if (children !== undefined) {
const newChildren = Array.isArray(children)
? [...children].reverse().map(processItemReverse).reverse()
: children
return <Tag {...{ attrs: getAttrs(opener) }}>
{ newChildren }
</Tag>
} else {
return <Tag/>
}
}
return item
}
const pass1 = convertHtmlToTree(html).map(processItem)
const pass2 = [...pass1].reverse().map(processItemReverse).reverse()
// DO NOT USE SLOTS they cause a re-render feedback loop here.
// slots updated -> rerender -> emit -> update up the tree -> rerender -> ...
// at least until vue3?
const result = <span class="RichContent">
{ pass2 }
</span>
const event = {
lastTags,
writtenMentions,
writtenTags,
invisibleMentions
}
// DO NOT MOVE TO UPDATE. BAD IDEA.
this.$emit('parseReady', event)
return result
}
})
const getLinkData = (attrs, children, index) => {
const stripTags = (item) => {
if (typeof item === 'string') {
return item
} else {
return item[1].map(stripTags).join('')
}
}
const textContent = children.map(stripTags).join('')
return {
index,
url: attrs.href,
tag: attrs['data-tag'],
content: flattenDeep(children).join(''),
textContent
}
}
/** Pre-processing HTML
*
* Currently this does one thing:
* - add green/cyantexting
*
* @param {String} html - raw HTML to process
* @param {Boolean} greentext - whether to enable greentexting or not
*/
export const preProcessPerLine = (html, greentext) => {
const greentextHandle = new Set(['p', 'div'])
const lines = convertHtmlToLines(html)
const newHtml = lines.reverse().map((item, index, array) => {
if (!item.text) return item
const string = item.text
// Greentext stuff
if (
// Only if greentext is engaged
greentext &&
// Only handle p's and divs. Don't want to affect blockquotes, code etc
item.level.every(l => greentextHandle.has(l)) &&
// Only if line begins with '>' or '<'
(string.includes('&gt;') || string.includes('&lt;'))
) {
const cleanedString = string.replace(/<[^>]+?>/gi, '') // remove all tags
.replace(/@\w+/gi, '') // remove mentions (even failed ones)
.trim()
if (cleanedString.startsWith('&gt;')) {
return `<span class='greentext'>${string}</span>`
} else if (cleanedString.startsWith('&lt;')) {
return `<span class='cyantext'>${string}</span>`
}
}
return string
}).reverse().join('')
return { newHtml }
}
@@ -0,0 +1,64 @@
.RichContent {
blockquote {
margin: 0.2em 0 0.2em 2em;
font-style: italic;
}
pre {
overflow: auto;
}
code,
samp,
kbd,
var,
pre {
font-family: var(--postCodeFont, monospace);
}
p {
margin: 0 0 1em 0;
}
p:last-child {
margin: 0 0 0 0;
}
h1 {
font-size: 1.1em;
line-height: 1.2em;
margin: 1.4em 0;
}
h2 {
font-size: 1.1em;
margin: 1em 0;
}
h3 {
font-size: 1em;
margin: 1.2em 0;
}
h4 {
margin: 1.1em 0;
}
.img {
display: inline-block;
}
.emoji {
display: inline-block;
width: var(--emoji-size, 32px);
height: var(--emoji-size, 32px);
}
.img,
video {
max-width: 100%;
max-height: 400px;
vertical-align: middle;
object-fit: contain;
}
}
+21
View File
@@ -0,0 +1,21 @@
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faChevronDown
} from '@fortawesome/free-solid-svg-icons'
library.add(
faChevronDown
)
export default {
model: {
prop: 'value',
event: 'change'
},
props: [
'value',
'disabled',
'unstyled',
'kind'
]
}
+62
View File
@@ -0,0 +1,62 @@
<template>
<label
class="Select input"
:class="{ disabled, unstyled }"
>
<select
:disabled="disabled"
:value="value"
@change="$emit('change', $event.target.value)"
>
<slot />
</select>
<FAIcon
class="select-down-icon"
icon="chevron-down"
/>
</label>
</template>
<script src="./select.js"> </script>
<style lang="scss">
@import '../../_variables.scss';
.Select {
padding: 0;
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: transparent;
border: none;
color: $fallback--text;
color: var(--inputText, --text, $fallback--text);
margin: 0;
padding: 0 2em 0 .2em;
font-family: sans-serif;
font-family: var(--inputFont, sans-serif);
font-size: 14px;
width: 100%;
z-index: 1;
height: 28px;
line-height: 16px;
}
.select-down-icon {
position: absolute;
top: 0;
bottom: 0;
right: 5px;
height: 100%;
color: $fallback--text;
color: var(--inputText, $fallback--text);
line-height: 28px;
z-index: 0;
pointer-events: none;
}
}
</style>
@@ -24,10 +24,7 @@
:items="items" :items="items"
:get-key="getKey" :get-key="getKey"
> >
<template <template v-slot:item="{item}">
slot="item"
slot-scope="{item}"
>
<div <div
class="selectable-list-item-inner" class="selectable-list-item-inner"
:class="{ 'selectable-list-item-selected-inner': isSelected(item) }" :class="{ 'selectable-list-item-selected-inner': isSelected(item) }"
@@ -44,7 +41,7 @@
/> />
</div> </div>
</template> </template>
<template slot="empty"> <template v-slot:empty>
<slot name="empty" /> <slot name="empty" />
</template> </template>
</List> </List>
@@ -0,0 +1,38 @@
import { get, set } from 'lodash'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import ModifiedIndicator from './modified_indicator.vue'
export default {
components: {
Checkbox,
ModifiedIndicator
},
props: [
'path',
'disabled'
],
computed: {
pathDefault () {
const [firstSegment, ...rest] = this.path.split('.')
return [firstSegment + 'DefaultValue', ...rest].join('.')
},
state () {
const value = get(this.$parent, this.path)
if (value === undefined) {
return this.defaultState
} else {
return value
}
},
defaultState () {
return get(this.$parent, this.pathDefault)
},
isChanged () {
return this.state !== this.defaultState
}
},
methods: {
update (e) {
set(this.$parent, this.path, e)
}
}
}
@@ -18,40 +18,4 @@
</label> </label>
</template> </template>
<script> <script src="./boolean_setting.js"></script>
import { get, set } from 'lodash'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import ModifiedIndicator from './modified_indicator.vue'
export default {
components: {
Checkbox,
ModifiedIndicator
},
props: [
'path',
'disabled'
],
computed: {
pathDefault () {
const [firstSegment, ...rest] = this.path.split('.')
return [firstSegment + 'DefaultValue', ...rest].join('.')
},
state () {
return get(this.$parent, this.path)
},
isChanged () {
return get(this.$parent, this.path) !== get(this.$parent, this.pathDefault)
}
},
methods: {
update (e) {
set(this.$parent, this.path, e)
}
}
}
</script>
<style lang="scss">
.BooleanSetting {
}
</style>
@@ -0,0 +1,39 @@
import { get, set } from 'lodash'
import Select from 'src/components/select/select.vue'
import ModifiedIndicator from './modified_indicator.vue'
export default {
components: {
Select,
ModifiedIndicator
},
props: [
'path',
'disabled',
'options'
],
computed: {
pathDefault () {
const [firstSegment, ...rest] = this.path.split('.')
return [firstSegment + 'DefaultValue', ...rest].join('.')
},
state () {
const value = get(this.$parent, this.path)
if (value === undefined) {
return this.defaultState
} else {
return value
}
},
defaultState () {
return get(this.$parent, this.pathDefault)
},
isChanged () {
return this.state !== this.defaultState
}
},
methods: {
update (e) {
set(this.$parent, this.path, e)
}
}
}
@@ -0,0 +1,29 @@
<template>
<label
class="ChoiceSetting"
>
<slot />
<Select
:value="state"
:disabled="disabled"
@change="update"
>
<option
v-for="option in options"
:key="option.key"
:value="option.value"
>
{{ option.label }}
{{ option.value === defaultState ? $t('settings.instance_default_simple') : '' }}
</option>
</Select>
<ModifiedIndicator :changed="isChanged" />
</label>
</template>
<script src="./choice_setting.js"></script>
<style lang="scss">
.ChoiceSetting {
}
</style>
@@ -6,18 +6,18 @@
<Popover <Popover
trigger="hover" trigger="hover"
> >
<span slot="trigger"> <template v-slot:trigger>
&nbsp; &nbsp;
<FAIcon <FAIcon
icon="wrench" icon="wrench"
:aria-label="$t('settings.setting_changed')"
/> />
</span> </template>
<div <template v-slot:content>
slot="content" <div class="modified-tooltip">
class="modified-tooltip"
>
{{ $t('settings.setting_changed') }} {{ $t('settings.setting_changed') }}
</div> </div>
</template>
</Popover> </Popover>
</span> </span>
</template> </template>
@@ -2,10 +2,55 @@ import Modal from 'src/components/modal/modal.vue'
import PanelLoading from 'src/components/panel_loading/panel_loading.vue' import PanelLoading from 'src/components/panel_loading/panel_loading.vue'
import AsyncComponentError from 'src/components/async_component_error/async_component_error.vue' import AsyncComponentError from 'src/components/async_component_error/async_component_error.vue'
import getResettableAsyncComponent from 'src/services/resettable_async_component.js' import getResettableAsyncComponent from 'src/services/resettable_async_component.js'
import Popover from '../popover/popover.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { cloneDeep } from 'lodash'
import {
newImporter,
newExporter
} from 'src/services/export_import/export_import.js'
import {
faTimes,
faFileUpload,
faFileDownload,
faChevronDown
} from '@fortawesome/free-solid-svg-icons'
import {
faWindowMinimize
} from '@fortawesome/free-regular-svg-icons'
const PLEROMAFE_SETTINGS_MAJOR_VERSION = 1
const PLEROMAFE_SETTINGS_MINOR_VERSION = 0
library.add(
faTimes,
faWindowMinimize,
faFileUpload,
faFileDownload,
faChevronDown
)
const SettingsModal = { const SettingsModal = {
data () {
return {
dataImporter: newImporter({
validator: this.importValidator,
onImport: this.onImport,
onImportFailure: this.onImportFailure
}),
dataThemeExporter: newExporter({
filename: 'pleromafe_settings.full',
getExportedObject: () => this.generateExport(true)
}),
dataExporter: newExporter({
filename: 'pleromafe_settings',
getExportedObject: () => this.generateExport()
})
}
},
components: { components: {
Modal, Modal,
Popover,
SettingsModalContent: getResettableAsyncComponent( SettingsModalContent: getResettableAsyncComponent(
() => import('./settings_modal_content.vue'), () => import('./settings_modal_content.vue'),
{ {
@@ -21,6 +66,85 @@ const SettingsModal = {
}, },
peekModal () { peekModal () {
this.$store.dispatch('togglePeekSettingsModal') this.$store.dispatch('togglePeekSettingsModal')
},
importValidator (data) {
if (!Array.isArray(data._pleroma_settings_version)) {
return {
messageKey: 'settings.file_import_export.invalid_file'
}
}
const [major, minor] = data._pleroma_settings_version
if (major > PLEROMAFE_SETTINGS_MAJOR_VERSION) {
return {
messageKey: 'settings.file_export_import.errors.file_too_new',
messageArgs: {
fileMajor: major,
feMajor: PLEROMAFE_SETTINGS_MAJOR_VERSION
}
}
}
if (major < PLEROMAFE_SETTINGS_MAJOR_VERSION) {
return {
messageKey: 'settings.file_export_import.errors.file_too_old',
messageArgs: {
fileMajor: major,
feMajor: PLEROMAFE_SETTINGS_MAJOR_VERSION
}
}
}
if (minor > PLEROMAFE_SETTINGS_MINOR_VERSION) {
this.$store.dispatch('pushGlobalNotice', {
level: 'warning',
messageKey: 'settings.file_export_import.errors.file_slightly_new'
})
}
return true
},
onImportFailure (result) {
if (result.error) {
this.$store.dispatch('pushGlobalNotice', { messageKey: 'settings.invalid_settings_imported', level: 'error' })
} else {
this.$store.dispatch('pushGlobalNotice', { ...result.validationResult, level: 'error' })
}
},
onImport (data) {
if (data) { this.$store.dispatch('loadSettings', data) }
},
restore () {
this.dataImporter.importData()
},
backup () {
this.dataExporter.exportData()
},
backupWithTheme () {
this.dataThemeExporter.exportData()
},
generateExport (theme = false) {
const { config } = this.$store.state
let sample = config
if (!theme) {
const ignoreList = new Set([
'customTheme',
'customThemeSource',
'colors'
])
sample = Object.fromEntries(
Object
.entries(sample)
.filter(([key]) => !ignoreList.has(key))
)
}
const clone = cloneDeep(sample)
clone._pleroma_settings_version = [
PLEROMAFE_SETTINGS_MAJOR_VERSION,
PLEROMAFE_SETTINGS_MINOR_VERSION
]
return clone
} }
}, },
computed: { computed: {
@@ -31,20 +31,84 @@
</transition> </transition>
<button <button
class="btn button-default" class="btn button-default"
:title="$t('general.peek')"
@click="peekModal" @click="peekModal"
> >
{{ $t('general.peek') }} <FAIcon
:icon="['far', 'window-minimize']"
fixed-width
/>
</button> </button>
<button <button
class="btn button-default" class="btn button-default"
:title="$t('general.close')"
@click="closeModal" @click="closeModal"
> >
{{ $t('general.close') }} <FAIcon
icon="times"
fixed-width
/>
</button> </button>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<SettingsModalContent v-if="modalOpenedOnce" /> <SettingsModalContent v-if="modalOpenedOnce" />
</div> </div>
<div class="panel-footer">
<Popover
class="export"
trigger="click"
placement="top"
:offset="{ y: 5, x: 5 }"
:bound-to="{ x: 'container' }"
remove-padding
>
<template v-slot:trigger>
<button
class="btn button-default"
:title="$t('general.close')"
>
<span>{{ $t("settings.file_export_import.backup_restore") }}</span>
<FAIcon
icon="chevron-down"
/>
</button>
</template>
<template v-slot:content="{close}">
<div class="dropdown-menu">
<button
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="backup"
@click="close"
>
<FAIcon
icon="file-download"
fixed-width
/><span>{{ $t("settings.file_export_import.backup_settings") }}</span>
</button>
<button
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="backupWithTheme"
@click="close"
>
<FAIcon
icon="file-download"
fixed-width
/><span>{{ $t("settings.file_export_import.backup_settings_theme") }}</span>
</button>
<button
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="restore"
@click="close"
>
<FAIcon
icon="file-upload"
fixed-width
/><span>{{ $t("settings.file_export_import.restore_settings") }}</span>
</button>
</div>
</template>
</Popover>
</div>
</div> </div>
</Modal> </Modal>
</template> </template>
@@ -7,13 +7,24 @@
margin: 1em 1em 1.4em; margin: 1em 1em 1.4em;
padding-bottom: 1.4em; padding-bottom: 1.4em;
> div { > div,
> label {
display: block;
margin-bottom: .5em; margin-bottom: .5em;
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
} }
.select-multiple {
display: flex;
.option-list {
margin: 0;
padding-left: .5em;
}
}
&:last-child { &:last-child {
border-bottom: none; border-bottom: none;
padding-bottom: 0; padding-bottom: 0;
@@ -1,24 +1,23 @@
import { filter, trim } from 'lodash' import { filter, trim } from 'lodash'
import BooleanSetting from '../helpers/boolean_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js' import SharedComputedObject from '../helpers/shared_computed_object.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faChevronDown
} from '@fortawesome/free-solid-svg-icons'
library.add(
faChevronDown
)
const FilteringTab = { const FilteringTab = {
data () { data () {
return { return {
muteWordsStringLocal: this.$store.getters.mergedConfig.muteWords.join('\n') muteWordsStringLocal: this.$store.getters.mergedConfig.muteWords.join('\n'),
replyVisibilityOptions: ['all', 'following', 'self'].map(mode => ({
key: mode,
value: mode,
label: this.$t(`settings.reply_visibility_${mode}`)
}))
} }
}, },
components: { components: {
BooleanSetting BooleanSetting,
ChoiceSetting
}, },
computed: { computed: {
...SharedComputedObject(), ...SharedComputedObject(),
@@ -36,29 +36,13 @@
</li> </li>
</ul> </ul>
</div> </div>
<div> <ChoiceSetting
{{ $t('settings.replies_in_timeline') }}
<label
for="replyVisibility"
class="select"
>
<select
id="replyVisibility" id="replyVisibility"
v-model="replyVisibility" path="replyVisibility"
:options="replyVisibilityOptions"
> >
<option {{ $t('settings.replies_in_timeline') }}
value="all" </ChoiceSetting>
selected
>{{ $t('settings.reply_visibility_all') }}</option>
<option value="following">{{ $t('settings.reply_visibility_following') }}</option>
<option value="self">{{ $t('settings.reply_visibility_self') }}</option>
</select>
<FAIcon
class="select-down-icon"
icon="chevron-down"
/>
</label>
</div>
<div> <div>
<BooleanSetting path="hidePostStats"> <BooleanSetting path="hidePostStats">
{{ $t('settings.hide_post_stats') }} {{ $t('settings.hide_post_stats') }}
@@ -1,21 +1,25 @@
import BooleanSetting from '../helpers/boolean_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue'
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue' import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js' import SharedComputedObject from '../helpers/shared_computed_object.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
faChevronDown,
faGlobe faGlobe
} from '@fortawesome/free-solid-svg-icons' } from '@fortawesome/free-solid-svg-icons'
library.add( library.add(
faChevronDown,
faGlobe faGlobe
) )
const GeneralTab = { const GeneralTab = {
data () { data () {
return { return {
subjectLineOptions: ['email', 'noop', 'masto'].map(mode => ({
key: mode,
value: mode,
label: this.$t(`settings.subject_line_${mode === 'masto' ? 'mastodon' : mode}`)
})),
loopSilentAvailable: loopSilentAvailable:
// Firefox // Firefox
Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') || Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') ||
@@ -27,17 +31,26 @@ const GeneralTab = {
}, },
components: { components: {
BooleanSetting, BooleanSetting,
ChoiceSetting,
InterfaceLanguageSwitcher InterfaceLanguageSwitcher
}, },
computed: { computed: {
postFormats () { postFormats () {
return this.$store.state.instance.postFormats || [] return this.$store.state.instance.postFormats || []
}, },
postContentOptions () {
return this.postFormats.map(format => ({
key: format,
value: format,
label: this.$t(`post_status.content_type["${format}"]`)
}))
},
instanceSpecificPanelPresent () { return this.$store.state.instance.showInstanceSpecificPanel }, instanceSpecificPanelPresent () { return this.$store.state.instance.showInstanceSpecificPanel },
instanceWallpaperUsed () { instanceWallpaperUsed () {
return this.$store.state.instance.background && return this.$store.state.instance.background &&
!this.$store.state.users.currentUser.background_image !this.$store.state.users.currentUser.background_image
}, },
instanceShoutboxPresent () { return this.$store.state.instance.shoutAvailable },
...SharedComputedObject() ...SharedComputedObject()
} }
} }
@@ -11,11 +11,21 @@
{{ $t('settings.hide_isp') }} {{ $t('settings.hide_isp') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li>
<BooleanSetting path="sidebarRight">
{{ $t('settings.right_sidebar') }}
</BooleanSetting>
</li>
<li v-if="instanceWallpaperUsed"> <li v-if="instanceWallpaperUsed">
<BooleanSetting path="hideInstanceWallpaper"> <BooleanSetting path="hideInstanceWallpaper">
{{ $t('settings.hide_wallpaper') }} {{ $t('settings.hide_wallpaper') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li v-if="instanceShoutboxPresent">
<BooleanSetting path="hideShoutbox">
{{ $t('settings.hide_shoutbox') }}
</BooleanSetting>
</li>
</ul> </ul>
</div> </div>
<div class="setting-item"> <div class="setting-item">
@@ -85,66 +95,36 @@
</BooleanSetting> </BooleanSetting>
</li> </li>
<li> <li>
<div> <ChoiceSetting
{{ $t('settings.subject_line_behavior') }}
<label
for="subjectLineBehavior"
class="select"
>
<select
id="subjectLineBehavior" id="subjectLineBehavior"
v-model="subjectLineBehavior" path="subjectLineBehavior"
:options="subjectLineOptions"
> >
<option value="email"> {{ $t('settings.subject_line_behavior') }}
{{ $t('settings.subject_line_email') }} </ChoiceSetting>
{{ subjectLineBehaviorDefaultValue == 'email' ? $t('settings.instance_default_simple') : '' }}
</option>
<option value="masto">
{{ $t('settings.subject_line_mastodon') }}
{{ subjectLineBehaviorDefaultValue == 'mastodon' ? $t('settings.instance_default_simple') : '' }}
</option>
<option value="noop">
{{ $t('settings.subject_line_noop') }}
{{ subjectLineBehaviorDefaultValue == 'noop' ? $t('settings.instance_default_simple') : '' }}
</option>
</select>
<FAIcon
class="select-down-icon"
icon="chevron-down"
/>
</label>
</div>
</li> </li>
<li v-if="postFormats.length > 0"> <li v-if="postFormats.length > 0">
<div> <ChoiceSetting
{{ $t('settings.post_status_content_type') }}
<label
for="postContentType"
class="select"
>
<select
id="postContentType" id="postContentType"
v-model="postContentType" path="postContentType"
:options="postContentOptions"
> >
<option {{ $t('settings.post_status_content_type') }}
v-for="postFormat in postFormats" </ChoiceSetting>
:key="postFormat"
:value="postFormat"
>
{{ $t(`post_status.content_type["${postFormat}"]`) }}
{{ postContentTypeDefaultValue === postFormat ? $t('settings.instance_default_simple') : '' }}
</option>
</select>
<FAIcon
class="select-down-icon"
icon="chevron-down"
/>
</label>
</div>
</li> </li>
<li> <li>
<BooleanSetting path="minimalScopesMode"> <BooleanSetting path="minimalScopesMode">
{{ $t('settings.minimal_scopes_mode') }} {{ minimalScopesModeDefaultValue }} {{ $t('settings.minimal_scopes_mode') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="sensitiveByDefault">
{{ $t('settings.sensitive_by_default') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="alwaysShowNewPostButton">
{{ $t('settings.always_show_post_button') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li> <li>
@@ -10,20 +10,18 @@
:query="queryUserIds" :query="queryUserIds"
:placeholder="$t('settings.search_user_to_block')" :placeholder="$t('settings.search_user_to_block')"
> >
<template v-slot="row">
<BlockCard <BlockCard
slot-scope="row"
:user-id="row.item" :user-id="row.item"
/> />
</template>
</Autosuggest> </Autosuggest>
</div> </div>
<BlockList <BlockList
:refresh="true" :refresh="true"
:get-key="i => i" :get-key="i => i"
> >
<template <template v-slot:header="{selected}">
slot="header"
slot-scope="{selected}"
>
<div class="bulk-actions"> <div class="bulk-actions">
<ProgressButton <ProgressButton
v-if="selected.length > 0" v-if="selected.length > 0"
@@ -31,7 +29,7 @@
:click="() => blockUsers(selected)" :click="() => blockUsers(selected)"
> >
{{ $t('user_card.block') }} {{ $t('user_card.block') }}
<template slot="progress"> <template v-slot:progress>
{{ $t('user_card.block_progress') }} {{ $t('user_card.block_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
@@ -41,19 +39,16 @@
:click="() => unblockUsers(selected)" :click="() => unblockUsers(selected)"
> >
{{ $t('user_card.unblock') }} {{ $t('user_card.unblock') }}
<template slot="progress"> <template v-slot:progress>
{{ $t('user_card.unblock_progress') }} {{ $t('user_card.unblock_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
</div> </div>
</template> </template>
<template <template v-slot:item="{item}">
slot="item"
slot-scope="{item}"
>
<BlockCard :user-id="item" /> <BlockCard :user-id="item" />
</template> </template>
<template slot="empty"> <template v-slot:empty>
{{ $t('settings.no_blocks') }} {{ $t('settings.no_blocks') }}
</template> </template>
</BlockList> </BlockList>
@@ -68,20 +63,18 @@
:query="queryUserIds" :query="queryUserIds"
:placeholder="$t('settings.search_user_to_mute')" :placeholder="$t('settings.search_user_to_mute')"
> >
<template v-slot="row">
<MuteCard <MuteCard
slot-scope="row"
:user-id="row.item" :user-id="row.item"
/> />
</template>
</Autosuggest> </Autosuggest>
</div> </div>
<MuteList <MuteList
:refresh="true" :refresh="true"
:get-key="i => i" :get-key="i => i"
> >
<template <template v-slot:header="{selected}">
slot="header"
slot-scope="{selected}"
>
<div class="bulk-actions"> <div class="bulk-actions">
<ProgressButton <ProgressButton
v-if="selected.length > 0" v-if="selected.length > 0"
@@ -89,7 +82,7 @@
:click="() => muteUsers(selected)" :click="() => muteUsers(selected)"
> >
{{ $t('user_card.mute') }} {{ $t('user_card.mute') }}
<template slot="progress"> <template v-slot:progress>
{{ $t('user_card.mute_progress') }} {{ $t('user_card.mute_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
@@ -99,19 +92,16 @@
:click="() => unmuteUsers(selected)" :click="() => unmuteUsers(selected)"
> >
{{ $t('user_card.unmute') }} {{ $t('user_card.unmute') }}
<template slot="progress"> <template v-slot:progress>
{{ $t('user_card.unmute_progress') }} {{ $t('user_card.unmute_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
</div> </div>
</template> </template>
<template <template v-slot:item="{item}">
slot="item"
slot-scope="{item}"
>
<MuteCard :user-id="item" /> <MuteCard :user-id="item" />
</template> </template>
<template slot="empty"> <template v-slot:empty>
{{ $t('settings.no_mutes') }} {{ $t('settings.no_mutes') }}
</template> </template>
</MuteList> </MuteList>
@@ -124,20 +114,18 @@
:query="queryKnownDomains" :query="queryKnownDomains"
:placeholder="$t('settings.type_domains_to_mute')" :placeholder="$t('settings.type_domains_to_mute')"
> >
<template v-slot="row">
<DomainMuteCard <DomainMuteCard
slot-scope="row"
:domain="row.item" :domain="row.item"
/> />
</template>
</Autosuggest> </Autosuggest>
</div> </div>
<DomainMuteList <DomainMuteList
:refresh="true" :refresh="true"
:get-key="i => i" :get-key="i => i"
> >
<template <template v-slot:header="{selected}">
slot="header"
slot-scope="{selected}"
>
<div class="bulk-actions"> <div class="bulk-actions">
<ProgressButton <ProgressButton
v-if="selected.length > 0" v-if="selected.length > 0"
@@ -145,19 +133,16 @@
:click="() => unmuteDomains(selected)" :click="() => unmuteDomains(selected)"
> >
{{ $t('domain_mute_card.unmute') }} {{ $t('domain_mute_card.unmute') }}
<template slot="progress"> <template v-slot:progress>
{{ $t('domain_mute_card.unmute_progress') }} {{ $t('domain_mute_card.unmute_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
</div> </div>
</template> </template>
<template <template v-slot:item="{item}">
slot="item"
slot-scope="{item}"
>
<DomainMuteCard :domain="item" /> <DomainMuteCard :domain="item" />
</template> </template>
<template slot="empty"> <template v-slot:empty>
{{ $t('settings.no_mutes') }} {{ $t('settings.no_mutes') }}
</template> </template>
</DomainMuteList> </DomainMuteList>
@@ -24,7 +24,7 @@
class="btn button-default" class="btn button-default"
@click="updateNotificationSettings" @click="updateNotificationSettings"
> >
{{ $t('general.submit') }} {{ $t('settings.save') }}
</button> </button>
</div> </div>
</div> </div>
@@ -24,7 +24,7 @@ library.add(
const ProfileTab = { const ProfileTab = {
data () { data () {
return { return {
newName: this.$store.state.users.currentUser.name, newName: this.$store.state.users.currentUser.name_unescaped,
newBio: unescape(this.$store.state.users.currentUser.description), newBio: unescape(this.$store.state.users.currentUser.description),
newLocked: this.$store.state.users.currentUser.locked, newLocked: this.$store.state.users.currentUser.locked,
newNoRichText: this.$store.state.users.currentUser.no_rich_text, newNoRichText: this.$store.state.users.currentUser.no_rich_text,
@@ -153,7 +153,7 @@
class="btn button-default" class="btn button-default"
@click="updateProfile" @click="updateProfile"
> >
{{ $t('general.submit') }} {{ $t('settings.save') }}
</button> </button>
</div> </div>
<div class="setting-item"> <div class="setting-item">
@@ -227,7 +227,7 @@
class="btn button-default" class="btn button-default"
@click="submitBanner(banner)" @click="submitBanner(banner)"
> >
{{ $t('general.submit') }} {{ $t('settings.save') }}
</button> </button>
</div> </div>
<div class="setting-item"> <div class="setting-item">
@@ -266,7 +266,7 @@
class="btn button-default" class="btn button-default"
@click="submitBackground(background)" @click="submitBackground(background)"
> >
{{ $t('general.submit') }} {{ $t('settings.save') }}
</button> </button>
</div> </div>
</div> </div>
@@ -22,7 +22,7 @@
class="btn button-default" class="btn button-default"
@click="changeEmail" @click="changeEmail"
> >
{{ $t('general.submit') }} {{ $t('settings.save') }}
</button> </button>
<p v-if="changedEmail"> <p v-if="changedEmail">
{{ $t('settings.changed_email') }} {{ $t('settings.changed_email') }}
@@ -60,7 +60,7 @@
class="btn button-default" class="btn button-default"
@click="changePassword" @click="changePassword"
> >
{{ $t('general.submit') }} {{ $t('settings.save') }}
</button> </button>
<p v-if="changedPassword"> <p v-if="changedPassword">
{{ $t('settings.changed_password') }} {{ $t('settings.changed_password') }}
@@ -133,7 +133,7 @@
class="btn button-default" class="btn button-default"
@click="confirmDelete" @click="confirmDelete"
> >
{{ $t('general.submit') }} {{ $t('settings.save') }}
</button> </button>
</div> </div>
</div> </div>
@@ -15,6 +15,10 @@ import {
shadows2to3, shadows2to3,
colors2to3 colors2to3
} from 'src/services/style_setter/style_setter.js' } from 'src/services/style_setter/style_setter.js'
import {
newImporter,
newExporter
} from 'src/services/export_import/export_import.js'
import { import {
SLOT_INHERITANCE SLOT_INHERITANCE
} from 'src/services/theme_data/pleromafe.js' } from 'src/services/theme_data/pleromafe.js'
@@ -31,18 +35,10 @@ import ShadowControl from 'src/components/shadow_control/shadow_control.vue'
import FontControl from 'src/components/font_control/font_control.vue' import FontControl from 'src/components/font_control/font_control.vue'
import ContrastRatio from 'src/components/contrast_ratio/contrast_ratio.vue' import ContrastRatio from 'src/components/contrast_ratio/contrast_ratio.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.js' import TabSwitcher from 'src/components/tab_switcher/tab_switcher.js'
import ExportImport from 'src/components/export_import/export_import.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue' import Checkbox from 'src/components/checkbox/checkbox.vue'
import Select from 'src/components/select/select.vue'
import Preview from './preview.vue' import Preview from './preview.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faChevronDown
} from '@fortawesome/free-solid-svg-icons'
library.add(
faChevronDown
)
// List of color values used in v1 // List of color values used in v1
const v1OnlyNames = [ const v1OnlyNames = [
@@ -67,8 +63,18 @@ const colorConvert = (color) => {
export default { export default {
data () { data () {
return { return {
themeImporter: newImporter({
validator: this.importValidator,
onImport: this.onImport,
onImportFailure: this.onImportFailure
}),
themeExporter: newExporter({
filename: 'pleroma_theme',
getExportedObject: () => this.exportedTheme
}),
availableStyles: [], availableStyles: [],
selected: this.$store.getters.mergedConfig.theme, selected: '',
selectedTheme: this.$store.getters.mergedConfig.theme,
themeWarning: undefined, themeWarning: undefined,
tempImportFile: undefined, tempImportFile: undefined,
engineVersion: 0, engineVersion: 0,
@@ -202,7 +208,7 @@ export default {
} }
}, },
selectedVersion () { selectedVersion () {
return Array.isArray(this.selected) ? 1 : 2 return Array.isArray(this.selectedTheme) ? 1 : 2
}, },
currentColors () { currentColors () {
return Object.keys(SLOT_INHERITANCE) return Object.keys(SLOT_INHERITANCE)
@@ -383,8 +389,8 @@ export default {
FontControl, FontControl,
TabSwitcher, TabSwitcher,
Preview, Preview,
ExportImport, Checkbox,
Checkbox Select
}, },
methods: { methods: {
loadTheme ( loadTheme (
@@ -469,7 +475,7 @@ export default {
this.loadThemeFromLocalStorage(false, true) this.loadThemeFromLocalStorage(false, true)
break break
case 'file': case 'file':
console.err('Forcing snapshout from file is not supported yet') console.error('Forcing snapshot from file is not supported yet')
break break
} }
this.dismissWarning() this.dismissWarning()
@@ -528,10 +534,15 @@ export default {
this.previewColors.mod this.previewColors.mod
) )
}, },
importTheme () { this.themeImporter.importData() },
exportTheme () { this.themeExporter.exportData() },
onImport (parsed, forceSource = false) { onImport (parsed, forceSource = false) {
this.tempImportFile = parsed this.tempImportFile = parsed
this.loadTheme(parsed, 'file', forceSource) this.loadTheme(parsed, 'file', forceSource)
}, },
onImportFailure (result) {
this.$store.dispatch('pushGlobalNotice', { messageKey: 'settings.invalid_theme_imported', level: 'error' })
},
importValidator (parsed) { importValidator (parsed) {
const version = parsed._pleroma_theme_version const version = parsed._pleroma_theme_version
return version >= 1 || version <= 2 return version >= 1 || version <= 2
@@ -735,6 +746,16 @@ export default {
} }
}, },
selected () { selected () {
this.selectedTheme = Object.entries(this.availableStyles).find(([k, s]) => {
if (Array.isArray(s)) {
console.log(s[0] === this.selected, this.selected)
return s[0] === this.selected
} else {
return s.name === this.selected
}
})[1]
},
selectedTheme () {
this.dismissWarning() this.dismissWarning()
if (this.selectedVersion === 1) { if (this.selectedVersion === 1) {
if (!this.keepRoundness) { if (!this.keepRoundness) {
@@ -752,17 +773,17 @@ export default {
if (!this.keepColor) { if (!this.keepColor) {
this.clearV1() this.clearV1()
this.bgColorLocal = this.selected[1] this.bgColorLocal = this.selectedTheme[1]
this.fgColorLocal = this.selected[2] this.fgColorLocal = this.selectedTheme[2]
this.textColorLocal = this.selected[3] this.textColorLocal = this.selectedTheme[3]
this.linkColorLocal = this.selected[4] this.linkColorLocal = this.selectedTheme[4]
this.cRedColorLocal = this.selected[5] this.cRedColorLocal = this.selectedTheme[5]
this.cGreenColorLocal = this.selected[6] this.cGreenColorLocal = this.selectedTheme[6]
this.cBlueColorLocal = this.selected[7] this.cBlueColorLocal = this.selectedTheme[7]
this.cOrangeColorLocal = this.selected[8] this.cOrangeColorLocal = this.selectedTheme[8]
} }
} else if (this.selectedVersion >= 2) { } else if (this.selectedVersion >= 2) {
this.normalizeLocalState(this.selected.theme, 2, this.selected.source) this.normalizeLocalState(this.selectedTheme.theme, 2, this.selectedTheme.source)
} }
} }
} }
@@ -270,6 +270,9 @@
.apply-container { .apply-container {
justify-content: center; justify-content: center;
position: absolute;
bottom: 8px;
right: 5px;
} }
.radius-item, .radius-item,
@@ -48,22 +48,14 @@
</template> </template>
</div> </div>
</div> </div>
<ExportImport <div class="top">
:export-object="exportedTheme"
:export-label="$t(&quot;settings.export_theme&quot;)"
:import-label="$t(&quot;settings.import_theme&quot;)"
:import-failed-text="$t(&quot;settings.invalid_theme_imported&quot;)"
:on-import="onImport"
:validator="importValidator"
>
<template slot="before">
<div class="presets"> <div class="presets">
{{ $t('settings.presets') }} {{ $t('settings.presets') }}
<label <label
for="preset-switcher" for="preset-switcher"
class="select" class="select"
> >
<select <Select
id="preset-switcher" id="preset-switcher"
v-model="selected" v-model="selected"
class="preset-switcher" class="preset-switcher"
@@ -71,7 +63,7 @@
<option <option
v-for="style in availableStyles" v-for="style in availableStyles"
:key="style.name" :key="style.name"
:value="style" :value="style.name || style[0]"
:style="{ :style="{
backgroundColor: style[1] || (style.theme || style.source).colors.bg, backgroundColor: style[1] || (style.theme || style.source).colors.bg,
color: style[3] || (style.theme || style.source).colors.text color: style[3] || (style.theme || style.source).colors.text
@@ -79,15 +71,24 @@
> >
{{ style[0] || style.name }} {{ style[0] || style.name }}
</option> </option>
</select> </Select>
<FAIcon
class="select-down-icon"
icon="chevron-down"
/>
</label> </label>
</div> </div>
</template> <div class="export-import">
</ExportImport> <button
class="btn button-default"
@click="importTheme"
>
{{ $t(&quot;settings.import_theme&quot;) }}
</button>
<button
class="btn button-default"
@click="exportTheme"
>
{{ $t(&quot;settings.export_theme&quot;) }}
</button>
</div>
</div>
</div> </div>
<div class="save-load-options"> <div class="save-load-options">
<span class="keep-option"> <span class="keep-option">
@@ -902,11 +903,7 @@
<div class="tab-header shadow-selector"> <div class="tab-header shadow-selector">
<div class="select-container"> <div class="select-container">
{{ $t('settings.style.shadows.component') }} {{ $t('settings.style.shadows.component') }}
<label <Select
for="shadow-switcher"
class="select"
>
<select
id="shadow-switcher" id="shadow-switcher"
v-model="shadowSelected" v-model="shadowSelected"
class="shadow-switcher" class="shadow-switcher"
@@ -918,12 +915,7 @@
> >
{{ $t('settings.style.shadows.components.' + shadow) }} {{ $t('settings.style.shadows.components.' + shadow) }}
</option> </option>
</select> </Select>
<FAIcon
class="select-down-icon"
icon="chevron-down"
/>
</label>
</div> </div>
<div class="override"> <div class="override">
<label <label
@@ -1,5 +1,6 @@
import ColorInput from '../color_input/color_input.vue' import ColorInput from '../color_input/color_input.vue'
import OpacityInput from '../opacity_input/opacity_input.vue' import OpacityInput from '../opacity_input/opacity_input.vue'
import Select from '../select/select.vue'
import { getCssShadow } from '../../services/style_setter/style_setter.js' import { getCssShadow } from '../../services/style_setter/style_setter.js'
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 { library } from '@fortawesome/fontawesome-svg-core'
@@ -45,7 +46,8 @@ export default {
}, },
components: { components: {
ColorInput, ColorInput,
OpacityInput OpacityInput,
Select
}, },
methods: { methods: {
add () { add () {

Some files were not shown because too many files have changed in this diff Show More