Merge branch 'develop' into 'icon_picker_admin_config'
# Conflicts: # app/soapbox/features/forms/index.js # app/soapbox/features/soapbox_config/index.js
This commit is contained in:
commit
21f68bf623
|
@ -188,6 +188,8 @@ Customization details can be found in the [Customization doc](docs/customization
|
|||
|
||||
Soapbox FE is based on [Gab Social](https://code.gab.com/gab/social/gab-social)'s frontend which is in turn based on [Mastodon](https://github.com/tootsuite/mastodon/)'s frontend.
|
||||
|
||||
- `static/sounds/chat.mp3` and `static/sounds/chat.oga` are from [notificationsounds.com](https://notificationsounds.com/notification-sounds/intuition-561) licensed under CC BY 4.0.
|
||||
|
||||
Soapbox FE is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 221 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 69 KiB |
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="63.161953mm"
|
||||
height="181.12712mm"
|
||||
viewBox="0 0 63.161953 181.12712"
|
||||
version="1.1"
|
||||
id="svg1199"
|
||||
inkscape:version="0.92.4 (unknown)"
|
||||
sodipodi:docname="spider.svg">
|
||||
<defs
|
||||
id="defs1193" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.35355339"
|
||||
inkscape:cx="188.63933"
|
||||
inkscape:cy="154.00309"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="705"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-global="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<metadata
|
||||
id="metadata1196">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-54.223528,-39.965002)">
|
||||
<path
|
||||
style="stroke-width:0.99999994"
|
||||
d="m 329.96094,151.04883 -7.95132,372.20898 c -30.02705,2.9243 -45.57271,12.92382 -64.25977,32.67188 -25.16762,33.38088 -18.43249,69.4298 -0.4707,100.66992 12.24879,17.03193 32.3984,27.97627 53.07033,34.15036 0,0 -5.52814,0.0857 -11.58984,9.46094 -18.91001,-5.43999 -38.07073,-9.95039 -57.14063,-14.82032 -10.49976,0.9523 -28.58163,18.8274 -36.67969,24.9004 0.27746,13.19067 1.67361,27.14135 3.33008,39.15039 1.1699,-1.57002 0.83916,-3.5804 1.03906,-5.40039 0.9,-10.79003 0.60034,-21.66016 1.99024,-32.41016 9.28,-6.03999 17.7906,-13.20072 26.7207,-19.7207 18.99884,1.97067 39.37112,9.36858 55.91016,13.35156 -0.49,2.41999 -1.38047,5.27974 -4.23047,5.67969 -18.4,4.60002 -36.81969,9.10007 -55.17969,13.83007 -4.86555,6.81697 -23.47884,41.76065 -22.16992,48 3.32807,9.25919 3.76668,29.35751 8.58984,35.70899 -0.65616,-11.27353 -1.26587,-23.12102 -2.88086,-33.41016 4.366,-15.53732 14.77165,-31.85507 21.21094,-44.72851 16.36837,-5.03014 33.6873,-8.93673 49.58008,-11.32032 -0.0299,3.31998 -0.081,6.66013 -0.20117,9.99024 -10.89612,8.5036 -30.45632,23.65603 -40.40821,30.44922 -2.57681,15.80044 -3.38605,33.75066 -4.2207,48.55078 2.50279,8.85582 13.19431,23.74406 18.17156,23.90823 -2.93816,-7.30216 -8.51629,-14.68425 -10.88086,-21.31836 -0.17087,-16.87764 2.99403,-32.98356 3.70114,-48.41015 11.61344,-9.80937 25.4679,-15.10577 35.89062,-24.25 2.26541,6.18864 7.32913,9.97253 10.32813,15.05859 -2.15,3.10001 -5.51922,5.79 -5.94922,9.75 2.88,4.37998 6.60955,8.25101 10.68945,11.54102 -0.85,-3.43 -2.26023,-6.68056 -3.24023,-10.06055 l 6.20117,-7.18945 c 10.18753,5.69922 19.39911,4.81707 28.78906,0.75976 2.12,2.45 4.30149,5.11952 5.27149,8.26953 -0.85,3.26 -2.7418,6.14966 -3.5918,9.42969 4.21,-3.40003 8.09071,-7.32883 11.4707,-11.54883 -0.72,-4.08 -4.4693,-6.80104 -5.27929,-10.79101 3.66,-4.43003 7.97023,-8.42941 10.24023,-13.85938 5.68622,5.4072 34.43902,22.24881 34.94922,26.88086 0.36518,16.19209 3.11897,31.74502 2,46.75 -4.46916,8.68536 -7.12999,16.57554 -14.39063,22.67969 9.90723,0.50906 17.4253,-14.74937 21.52152,-22.69328 -0.18697,-17.91233 -0.74645,-33.39521 -1.16992,-49.66992 -13.47001,-10.57002 -27.16094,-20.89017 -40.46094,-31.66016 0.59,-3.81003 0.49976,-7.6583 0.50977,-11.48828 15.73,4.66001 31.80992,8.14868 47.66992,12.38867 7.58475,10.99663 15.5151,31.43552 20.24023,42.75977 0.43698,13.66208 -3.68079,27.5449 -4.08008,40.14062 1.49998,-1.33999 1.6498,-3.42013 2.17969,-5.24023 1.88197,-11.16719 9.61842,-29.63645 8.13086,-37.92969 -6.21997,-14.23003 -11.95978,-28.75009 -18.42969,-42.83008 -19.30273,-6.68031 -40.27482,-12.85569 -58.39062,-17.73047 -0.65,-1.72002 -1.1801,-3.47951 -1.5,-5.26953 17.78,-3.66999 35.60009,-7.40034 53.33008,-11.32031 5.35892,-0.14205 29.14876,22.09172 28.98047,23.98047 1.30016,6.78634 -2.08415,29.71011 1.61914,33.13086 2.05988,-11.02999 3.41097,-22.17002 5.12109,-33.25 -0.32862,-6.33401 -29.16337,-28.29439 -33.91016,-30.79102 -20.42635,4.13166 -40.67884,9.74123 -59.80078,12.63086 -5.16629,-4.96887 -11.64306,-7.41991 -17.4707,-10.33984 26.33,-1.87998 52.09,-16.02008 66.25,-38.58008 9.5235,-13.96814 12.87637,-29.769 13.1992,-45.79102 0.33714,-20.46694 -8.12112,-40.39069 -21.6211,-55.4707 -18.78284,-17.43524 -31.48782,-23.12017 -55.43945,-26.73828 l 6.93151,-372.80078 z"
|
||||
id="path1768"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
|
||||
transform="scale(0.26458333)" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.2 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 77 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="svg46269" viewBox="0 0 340.00001 394.2857" height="111.27618mm" width="95.955559mm">
|
||||
<defs id="defs46271">
|
||||
<linearGradient id="linearGradient46839">
|
||||
<stop id="stop46841" offset="0" style="stop-color:#904700;stop-opacity:1;"/>
|
||||
<stop id="stop46843" offset="1" style="stop-color:#904700;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient46831">
|
||||
<stop id="stop46833" offset="0" style="stop-color:#904700;stop-opacity:1;"/>
|
||||
<stop id="stop46835" offset="1" style="stop-color:#904700;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient46823">
|
||||
<stop id="stop46825" offset="0" style="stop-color:#904700;stop-opacity:1;"/>
|
||||
<stop id="stop46827" offset="1" style="stop-color:#904700;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<radialGradient gradientTransform="matrix(4.9019612,0,0,4.9019612,-600.72836,-1264.1473)" gradientUnits="userSpaceOnUse" r="72.85714" fy="330.93362" fx="152.85715" cy="330.93362" cx="152.85715" id="radialGradient46829" xlink:href="#linearGradient46823"/>
|
||||
<radialGradient gradientTransform="matrix(3.3636365,0,0,3.3636365,-602.85717,-938.05096)" gradientUnits="userSpaceOnUse" r="62.857143" fy="429.50507" fx="251.42857" cy="429.50507" cx="251.42857" id="radialGradient46837" xlink:href="#linearGradient46831"/>
|
||||
<radialGradient gradientTransform="matrix(1.7317072,0,0,1.7317072,-145.78397,-287.44272)" gradientUnits="userSpaceOnUse" r="58.57143" fy="470.93369" fx="132.85715" cy="470.93369" cx="132.85715" id="radialGradient46845" xlink:href="#linearGradient46839"/>
|
||||
</defs>
|
||||
<metadata id="metadata46274">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g transform="translate(-8.5714264,-218.07648)" id="layer1">
|
||||
<circle r="140" cy="358.07648" cx="148.57143" id="path46817" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient46829);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:20, 5;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"/>
|
||||
<circle r="105.71429" cy="506.64789" cx="242.85715" id="path46819" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient46837);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:20, 5;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"/>
|
||||
<circle r="58.57143" cy="528.07654" cx="84.285713" id="path46821" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient46845);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:20, 5;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.4 KiB |
|
@ -0,0 +1,739 @@
|
|||
{
|
||||
"ancestors": [
|
||||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"avatar_static": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"follow_requests_count": 0,
|
||||
"followers_count": 725,
|
||||
"following_count": 1211,
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"locked": false,
|
||||
"note": "Fediverse developer. I come in peace.<br/><br/><a class=\"hashtag\" data-tag=\"vegan\" href=\"https://gleasonator.com/tag/vegan\">#vegan</a> <a class=\"hashtag\" data-tag=\"freeculture\" href=\"https://gleasonator.com/tag/freeculture\">#freeculture</a> <a class=\"hashtag\" data-tag=\"atheist\" href=\"https://gleasonator.com/tag/atheist\">#atheist</a> <a class=\"hashtag\" data-tag=\"antiporn\" href=\"https://gleasonator.com/tag/antiporn\">#antiporn</a> <a class=\"hashtag\" data-tag=\"gendercritical\" href=\"https://gleasonator.com/tag/gendercritical\">#gendercritical</a>.<br/><br/>Boosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"allow_following_move": true,
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"confirmation_pending": false,
|
||||
"deactivated": false,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_moderator": false,
|
||||
"notification_settings": {
|
||||
"block_from_strangers": false,
|
||||
"hide_notification_contents": false
|
||||
},
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": [],
|
||||
"unread_conversation_count": 95,
|
||||
"unread_notifications_count": 0
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"note": "Fediverse developer. I come in peace.\r\n\r\n#vegan #freeculture #atheist #antiporn #gendercritical.\r\n\r\nBoosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false,
|
||||
"no_rich_text": false,
|
||||
"show_role": true
|
||||
},
|
||||
"privacy": "public",
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 9157,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>A</p>",
|
||||
"created_at": "2020-09-18T20:07:10.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "9zIH6kDXA10YqhMKqO",
|
||||
"in_reply_to_account_id": null,
|
||||
"in_reply_to_id": null,
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "A"
|
||||
},
|
||||
"conversation_id": 5089485,
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": null,
|
||||
"local": true,
|
||||
"parent_visible": false,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/9995c074-2ff6-4a01-b596-7ef6971ed5d2",
|
||||
"url": "https://gleasonator.com/notice/9zIH6kDXA10YqhMKqO",
|
||||
"visibility": "direct"
|
||||
},
|
||||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"avatar_static": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"follow_requests_count": 0,
|
||||
"followers_count": 725,
|
||||
"following_count": 1211,
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"locked": false,
|
||||
"note": "Fediverse developer. I come in peace.<br/><br/><a class=\"hashtag\" data-tag=\"vegan\" href=\"https://gleasonator.com/tag/vegan\">#vegan</a> <a class=\"hashtag\" data-tag=\"freeculture\" href=\"https://gleasonator.com/tag/freeculture\">#freeculture</a> <a class=\"hashtag\" data-tag=\"atheist\" href=\"https://gleasonator.com/tag/atheist\">#atheist</a> <a class=\"hashtag\" data-tag=\"antiporn\" href=\"https://gleasonator.com/tag/antiporn\">#antiporn</a> <a class=\"hashtag\" data-tag=\"gendercritical\" href=\"https://gleasonator.com/tag/gendercritical\">#gendercritical</a>.<br/><br/>Boosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"allow_following_move": true,
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"confirmation_pending": false,
|
||||
"deactivated": false,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_moderator": false,
|
||||
"notification_settings": {
|
||||
"block_from_strangers": false,
|
||||
"hide_notification_contents": false
|
||||
},
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": [],
|
||||
"unread_conversation_count": 95,
|
||||
"unread_notifications_count": 0
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"note": "Fediverse developer. I come in peace.\r\n\r\n#vegan #freeculture #atheist #antiporn #gendercritical.\r\n\r\nBoosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false,
|
||||
"no_rich_text": false,
|
||||
"show_role": true
|
||||
},
|
||||
"privacy": "public",
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 9157,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>B</p>",
|
||||
"created_at": "2020-09-18T20:07:18.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "9zIH7PUdhK3Ircg4hM",
|
||||
"in_reply_to_account_id": "9v5bmRalQvjOy0ECcC",
|
||||
"in_reply_to_id": "9zIH6kDXA10YqhMKqO",
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "alex",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "B"
|
||||
},
|
||||
"conversation_id": 5089485,
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": "alex",
|
||||
"local": true,
|
||||
"parent_visible": true,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/992ca99a-425d-46eb-b094-60412e9fb141",
|
||||
"url": "https://gleasonator.com/notice/9zIH7PUdhK3Ircg4hM",
|
||||
"visibility": "direct"
|
||||
},
|
||||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"avatar_static": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"follow_requests_count": 0,
|
||||
"followers_count": 725,
|
||||
"following_count": 1211,
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"locked": false,
|
||||
"note": "Fediverse developer. I come in peace.<br/><br/><a class=\"hashtag\" data-tag=\"vegan\" href=\"https://gleasonator.com/tag/vegan\">#vegan</a> <a class=\"hashtag\" data-tag=\"freeculture\" href=\"https://gleasonator.com/tag/freeculture\">#freeculture</a> <a class=\"hashtag\" data-tag=\"atheist\" href=\"https://gleasonator.com/tag/atheist\">#atheist</a> <a class=\"hashtag\" data-tag=\"antiporn\" href=\"https://gleasonator.com/tag/antiporn\">#antiporn</a> <a class=\"hashtag\" data-tag=\"gendercritical\" href=\"https://gleasonator.com/tag/gendercritical\">#gendercritical</a>.<br/><br/>Boosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"allow_following_move": true,
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"confirmation_pending": false,
|
||||
"deactivated": false,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_moderator": false,
|
||||
"notification_settings": {
|
||||
"block_from_strangers": false,
|
||||
"hide_notification_contents": false
|
||||
},
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": [],
|
||||
"unread_conversation_count": 95,
|
||||
"unread_notifications_count": 0
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"note": "Fediverse developer. I come in peace.\r\n\r\n#vegan #freeculture #atheist #antiporn #gendercritical.\r\n\r\nBoosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false,
|
||||
"no_rich_text": false,
|
||||
"show_role": true
|
||||
},
|
||||
"privacy": "public",
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 9157,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>C</p>",
|
||||
"created_at": "2020-09-18T20:07:22.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "9zIH7mMGgc1RmJwDLM",
|
||||
"in_reply_to_account_id": "9v5bmRalQvjOy0ECcC",
|
||||
"in_reply_to_id": "9zIH6kDXA10YqhMKqO",
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "alex",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "C"
|
||||
},
|
||||
"conversation_id": 5089485,
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": "alex",
|
||||
"local": true,
|
||||
"parent_visible": true,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/a2c25ef5-a40e-4098-b07e-b468989ef749",
|
||||
"url": "https://gleasonator.com/notice/9zIH7mMGgc1RmJwDLM",
|
||||
"visibility": "direct"
|
||||
}
|
||||
],
|
||||
"descendants": [
|
||||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"avatar_static": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"follow_requests_count": 0,
|
||||
"followers_count": 725,
|
||||
"following_count": 1211,
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"locked": false,
|
||||
"note": "Fediverse developer. I come in peace.<br/><br/><a class=\"hashtag\" data-tag=\"vegan\" href=\"https://gleasonator.com/tag/vegan\">#vegan</a> <a class=\"hashtag\" data-tag=\"freeculture\" href=\"https://gleasonator.com/tag/freeculture\">#freeculture</a> <a class=\"hashtag\" data-tag=\"atheist\" href=\"https://gleasonator.com/tag/atheist\">#atheist</a> <a class=\"hashtag\" data-tag=\"antiporn\" href=\"https://gleasonator.com/tag/antiporn\">#antiporn</a> <a class=\"hashtag\" data-tag=\"gendercritical\" href=\"https://gleasonator.com/tag/gendercritical\">#gendercritical</a>.<br/><br/>Boosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"allow_following_move": true,
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"confirmation_pending": false,
|
||||
"deactivated": false,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_moderator": false,
|
||||
"notification_settings": {
|
||||
"block_from_strangers": false,
|
||||
"hide_notification_contents": false
|
||||
},
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": [],
|
||||
"unread_conversation_count": 95,
|
||||
"unread_notifications_count": 0
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"note": "Fediverse developer. I come in peace.\r\n\r\n#vegan #freeculture #atheist #antiporn #gendercritical.\r\n\r\nBoosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false,
|
||||
"no_rich_text": false,
|
||||
"show_role": true
|
||||
},
|
||||
"privacy": "public",
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 9157,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>E</p>",
|
||||
"created_at": "2020-09-18T20:07:38.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "9zIH9GTCDWEFSRt2um",
|
||||
"in_reply_to_account_id": "9v5bmRalQvjOy0ECcC",
|
||||
"in_reply_to_id": "9zIH7PUdhK3Ircg4hM",
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "alex",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "E"
|
||||
},
|
||||
"conversation_id": 5089485,
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": "alex",
|
||||
"local": true,
|
||||
"parent_visible": true,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/a1e45493-2158-4f11-88ca-ba621429dbe5",
|
||||
"url": "https://gleasonator.com/notice/9zIH9GTCDWEFSRt2um",
|
||||
"visibility": "direct"
|
||||
},
|
||||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"avatar_static": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"follow_requests_count": 0,
|
||||
"followers_count": 725,
|
||||
"following_count": 1211,
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"locked": false,
|
||||
"note": "Fediverse developer. I come in peace.<br/><br/><a class=\"hashtag\" data-tag=\"vegan\" href=\"https://gleasonator.com/tag/vegan\">#vegan</a> <a class=\"hashtag\" data-tag=\"freeculture\" href=\"https://gleasonator.com/tag/freeculture\">#freeculture</a> <a class=\"hashtag\" data-tag=\"atheist\" href=\"https://gleasonator.com/tag/atheist\">#atheist</a> <a class=\"hashtag\" data-tag=\"antiporn\" href=\"https://gleasonator.com/tag/antiporn\">#antiporn</a> <a class=\"hashtag\" data-tag=\"gendercritical\" href=\"https://gleasonator.com/tag/gendercritical\">#gendercritical</a>.<br/><br/>Boosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"allow_following_move": true,
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"confirmation_pending": false,
|
||||
"deactivated": false,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_moderator": false,
|
||||
"notification_settings": {
|
||||
"block_from_strangers": false,
|
||||
"hide_notification_contents": false
|
||||
},
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": [],
|
||||
"unread_conversation_count": 95,
|
||||
"unread_notifications_count": 0
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"note": "Fediverse developer. I come in peace.\r\n\r\n#vegan #freeculture #atheist #antiporn #gendercritical.\r\n\r\nBoosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false,
|
||||
"no_rich_text": false,
|
||||
"show_role": true
|
||||
},
|
||||
"privacy": "public",
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 9157,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>F</p>",
|
||||
"created_at": "2020-09-18T20:07:42.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "9zIH9fhaP9atiJoOJc",
|
||||
"in_reply_to_account_id": "9v5bmRalQvjOy0ECcC",
|
||||
"in_reply_to_id": "9zIH8WYwtnUx4yDzUm",
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "alex",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "F"
|
||||
},
|
||||
"conversation_id": 5089485,
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": "alex",
|
||||
"local": true,
|
||||
"parent_visible": true,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/ee661cf9-35d4-4e84-88ff-13b5950f7556",
|
||||
"url": "https://gleasonator.com/notice/9zIH9fhaP9atiJoOJc",
|
||||
"visibility": "direct"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,739 @@
|
|||
{
|
||||
"ancestors": [
|
||||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"avatar_static": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"follow_requests_count": 0,
|
||||
"followers_count": 725,
|
||||
"following_count": 1211,
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"locked": false,
|
||||
"note": "Fediverse developer. I come in peace.<br/><br/><a class=\"hashtag\" data-tag=\"vegan\" href=\"https://gleasonator.com/tag/vegan\">#vegan</a> <a class=\"hashtag\" data-tag=\"freeculture\" href=\"https://gleasonator.com/tag/freeculture\">#freeculture</a> <a class=\"hashtag\" data-tag=\"atheist\" href=\"https://gleasonator.com/tag/atheist\">#atheist</a> <a class=\"hashtag\" data-tag=\"antiporn\" href=\"https://gleasonator.com/tag/antiporn\">#antiporn</a> <a class=\"hashtag\" data-tag=\"gendercritical\" href=\"https://gleasonator.com/tag/gendercritical\">#gendercritical</a>.<br/><br/>Boosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"allow_following_move": true,
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"confirmation_pending": false,
|
||||
"deactivated": false,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_moderator": false,
|
||||
"notification_settings": {
|
||||
"block_from_strangers": false,
|
||||
"hide_notification_contents": false
|
||||
},
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": [],
|
||||
"unread_conversation_count": 95,
|
||||
"unread_notifications_count": 0
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"note": "Fediverse developer. I come in peace.\r\n\r\n#vegan #freeculture #atheist #antiporn #gendercritical.\r\n\r\nBoosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false,
|
||||
"no_rich_text": false,
|
||||
"show_role": true
|
||||
},
|
||||
"privacy": "public",
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 9157,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>A</p>",
|
||||
"created_at": "2020-09-18T20:07:10.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "9zIH6kDXA10YqhMKqO",
|
||||
"in_reply_to_account_id": null,
|
||||
"in_reply_to_id": null,
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "A"
|
||||
},
|
||||
"conversation_id": 5089485,
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": null,
|
||||
"local": true,
|
||||
"parent_visible": false,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/9995c074-2ff6-4a01-b596-7ef6971ed5d2",
|
||||
"url": "https://gleasonator.com/notice/9zIH6kDXA10YqhMKqO",
|
||||
"visibility": "direct"
|
||||
}
|
||||
],
|
||||
"descendants": [
|
||||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"avatar_static": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"follow_requests_count": 0,
|
||||
"followers_count": 725,
|
||||
"following_count": 1211,
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"locked": false,
|
||||
"note": "Fediverse developer. I come in peace.<br/><br/><a class=\"hashtag\" data-tag=\"vegan\" href=\"https://gleasonator.com/tag/vegan\">#vegan</a> <a class=\"hashtag\" data-tag=\"freeculture\" href=\"https://gleasonator.com/tag/freeculture\">#freeculture</a> <a class=\"hashtag\" data-tag=\"atheist\" href=\"https://gleasonator.com/tag/atheist\">#atheist</a> <a class=\"hashtag\" data-tag=\"antiporn\" href=\"https://gleasonator.com/tag/antiporn\">#antiporn</a> <a class=\"hashtag\" data-tag=\"gendercritical\" href=\"https://gleasonator.com/tag/gendercritical\">#gendercritical</a>.<br/><br/>Boosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"allow_following_move": true,
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"confirmation_pending": false,
|
||||
"deactivated": false,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_moderator": false,
|
||||
"notification_settings": {
|
||||
"block_from_strangers": false,
|
||||
"hide_notification_contents": false
|
||||
},
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": [],
|
||||
"unread_conversation_count": 95,
|
||||
"unread_notifications_count": 0
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"note": "Fediverse developer. I come in peace.\r\n\r\n#vegan #freeculture #atheist #antiporn #gendercritical.\r\n\r\nBoosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false,
|
||||
"no_rich_text": false,
|
||||
"show_role": true
|
||||
},
|
||||
"privacy": "public",
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 9157,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>C</p>",
|
||||
"created_at": "2020-09-18T20:07:22.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "9zIH7mMGgc1RmJwDLM",
|
||||
"in_reply_to_account_id": "9v5bmRalQvjOy0ECcC",
|
||||
"in_reply_to_id": "9zIH6kDXA10YqhMKqO",
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "alex",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "C"
|
||||
},
|
||||
"conversation_id": 5089485,
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": "alex",
|
||||
"local": true,
|
||||
"parent_visible": true,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/a2c25ef5-a40e-4098-b07e-b468989ef749",
|
||||
"url": "https://gleasonator.com/notice/9zIH7mMGgc1RmJwDLM",
|
||||
"visibility": "direct"
|
||||
},
|
||||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"avatar_static": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"follow_requests_count": 0,
|
||||
"followers_count": 725,
|
||||
"following_count": 1211,
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"locked": false,
|
||||
"note": "Fediverse developer. I come in peace.<br/><br/><a class=\"hashtag\" data-tag=\"vegan\" href=\"https://gleasonator.com/tag/vegan\">#vegan</a> <a class=\"hashtag\" data-tag=\"freeculture\" href=\"https://gleasonator.com/tag/freeculture\">#freeculture</a> <a class=\"hashtag\" data-tag=\"atheist\" href=\"https://gleasonator.com/tag/atheist\">#atheist</a> <a class=\"hashtag\" data-tag=\"antiporn\" href=\"https://gleasonator.com/tag/antiporn\">#antiporn</a> <a class=\"hashtag\" data-tag=\"gendercritical\" href=\"https://gleasonator.com/tag/gendercritical\">#gendercritical</a>.<br/><br/>Boosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"allow_following_move": true,
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"confirmation_pending": false,
|
||||
"deactivated": false,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_moderator": false,
|
||||
"notification_settings": {
|
||||
"block_from_strangers": false,
|
||||
"hide_notification_contents": false
|
||||
},
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": [],
|
||||
"unread_conversation_count": 95,
|
||||
"unread_notifications_count": 0
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"note": "Fediverse developer. I come in peace.\r\n\r\n#vegan #freeculture #atheist #antiporn #gendercritical.\r\n\r\nBoosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false,
|
||||
"no_rich_text": false,
|
||||
"show_role": true
|
||||
},
|
||||
"privacy": "public",
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 9157,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>D</p>",
|
||||
"created_at": "2020-09-18T20:07:30.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "9zIH8WYwtnUx4yDzUm",
|
||||
"in_reply_to_account_id": "9v5bmRalQvjOy0ECcC",
|
||||
"in_reply_to_id": "9zIH7PUdhK3Ircg4hM",
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "alex",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "D"
|
||||
},
|
||||
"conversation_id": 5089485,
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": "alex",
|
||||
"local": true,
|
||||
"parent_visible": true,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/bb423adc-ed86-42d8-942e-84efbe7b1acf",
|
||||
"url": "https://gleasonator.com/notice/9zIH8WYwtnUx4yDzUm",
|
||||
"visibility": "direct"
|
||||
},
|
||||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"avatar_static": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"follow_requests_count": 0,
|
||||
"followers_count": 725,
|
||||
"following_count": 1211,
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"locked": false,
|
||||
"note": "Fediverse developer. I come in peace.<br/><br/><a class=\"hashtag\" data-tag=\"vegan\" href=\"https://gleasonator.com/tag/vegan\">#vegan</a> <a class=\"hashtag\" data-tag=\"freeculture\" href=\"https://gleasonator.com/tag/freeculture\">#freeculture</a> <a class=\"hashtag\" data-tag=\"atheist\" href=\"https://gleasonator.com/tag/atheist\">#atheist</a> <a class=\"hashtag\" data-tag=\"antiporn\" href=\"https://gleasonator.com/tag/antiporn\">#antiporn</a> <a class=\"hashtag\" data-tag=\"gendercritical\" href=\"https://gleasonator.com/tag/gendercritical\">#gendercritical</a>.<br/><br/>Boosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"allow_following_move": true,
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"confirmation_pending": false,
|
||||
"deactivated": false,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_moderator": false,
|
||||
"notification_settings": {
|
||||
"block_from_strangers": false,
|
||||
"hide_notification_contents": false
|
||||
},
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": [],
|
||||
"unread_conversation_count": 95,
|
||||
"unread_notifications_count": 0
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"note": "Fediverse developer. I come in peace.\r\n\r\n#vegan #freeculture #atheist #antiporn #gendercritical.\r\n\r\nBoosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false,
|
||||
"no_rich_text": false,
|
||||
"show_role": true
|
||||
},
|
||||
"privacy": "public",
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 9157,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>E</p>",
|
||||
"created_at": "2020-09-18T20:07:38.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "9zIH9GTCDWEFSRt2um",
|
||||
"in_reply_to_account_id": "9v5bmRalQvjOy0ECcC",
|
||||
"in_reply_to_id": "9zIH7PUdhK3Ircg4hM",
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "alex",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "E"
|
||||
},
|
||||
"conversation_id": 5089485,
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": "alex",
|
||||
"local": true,
|
||||
"parent_visible": true,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/a1e45493-2158-4f11-88ca-ba621429dbe5",
|
||||
"url": "https://gleasonator.com/notice/9zIH9GTCDWEFSRt2um",
|
||||
"visibility": "direct"
|
||||
},
|
||||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"avatar_static": "https://media.gleasonator.com/26f0ca4ef51f7047829fdb65a43cb7d0304413ce0a5d00dd1638458994608718.jpg",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"follow_requests_count": 0,
|
||||
"followers_count": 725,
|
||||
"following_count": 1211,
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"locked": false,
|
||||
"note": "Fediverse developer. I come in peace.<br/><br/><a class=\"hashtag\" data-tag=\"vegan\" href=\"https://gleasonator.com/tag/vegan\">#vegan</a> <a class=\"hashtag\" data-tag=\"freeculture\" href=\"https://gleasonator.com/tag/freeculture\">#freeculture</a> <a class=\"hashtag\" data-tag=\"atheist\" href=\"https://gleasonator.com/tag/atheist\">#atheist</a> <a class=\"hashtag\" data-tag=\"antiporn\" href=\"https://gleasonator.com/tag/antiporn\">#antiporn</a> <a class=\"hashtag\" data-tag=\"gendercritical\" href=\"https://gleasonator.com/tag/gendercritical\">#gendercritical</a>.<br/><br/>Boosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"allow_following_move": true,
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"confirmation_pending": false,
|
||||
"deactivated": false,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_moderator": false,
|
||||
"notification_settings": {
|
||||
"block_from_strangers": false,
|
||||
"hide_notification_contents": false
|
||||
},
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": [],
|
||||
"unread_conversation_count": 95,
|
||||
"unread_notifications_count": 0
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
}
|
||||
],
|
||||
"note": "Fediverse developer. I come in peace.\r\n\r\n#vegan #freeculture #atheist #antiporn #gendercritical.\r\n\r\nBoosts ≠ endorsements.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false,
|
||||
"no_rich_text": false,
|
||||
"show_role": true
|
||||
},
|
||||
"privacy": "public",
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 9157,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>F</p>",
|
||||
"created_at": "2020-09-18T20:07:42.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "9zIH9fhaP9atiJoOJc",
|
||||
"in_reply_to_account_id": "9v5bmRalQvjOy0ECcC",
|
||||
"in_reply_to_id": "9zIH8WYwtnUx4yDzUm",
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "alex",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "F"
|
||||
},
|
||||
"conversation_id": 5089485,
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": "alex",
|
||||
"local": true,
|
||||
"parent_visible": true,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/ee661cf9-35d4-4e84-88ff-13b5950f7556",
|
||||
"url": "https://gleasonator.com/notice/9zIH9fhaP9atiJoOJc",
|
||||
"visibility": "direct"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -23,6 +23,10 @@ export const CHAT_READ_REQUEST = 'CHAT_READ_REQUEST';
|
|||
export const CHAT_READ_SUCCESS = 'CHAT_READ_SUCCESS';
|
||||
export const CHAT_READ_FAIL = 'CHAT_READ_FAIL';
|
||||
|
||||
export const CHAT_MESSAGE_DELETE_REQUEST = 'CHAT_MESSAGE_DELETE_REQUEST';
|
||||
export const CHAT_MESSAGE_DELETE_SUCCESS = 'CHAT_MESSAGE_DELETE_SUCCESS';
|
||||
export const CHAT_MESSAGE_DELETE_FAIL = 'CHAT_MESSAGE_DELETE_FAIL';
|
||||
|
||||
export function fetchChats() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: CHATS_FETCH_REQUEST });
|
||||
|
@ -150,3 +154,14 @@ export function markChatRead(chatId, lastReadId) {
|
|||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteChatMessage(chatId, messageId) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: CHAT_MESSAGE_DELETE_REQUEST, chatId, messageId });
|
||||
api(getState).delete(`/api/v1/pleroma/chats/${chatId}/messages/${messageId}`).then(({ data }) => {
|
||||
dispatch({ type: CHAT_MESSAGE_DELETE_SUCCESS, chatId, messageId, chatMessage: data });
|
||||
}).catch(error => {
|
||||
dispatch({ type: CHAT_MESSAGE_DELETE_FAIL, chatId, messageId, error });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ export function importFetchedAccounts(accounts) {
|
|||
const normalAccounts = [];
|
||||
|
||||
function processAccount(account) {
|
||||
if (!account.id) return;
|
||||
|
||||
pushUnique(normalAccounts, normalizeAccount(account));
|
||||
|
||||
if (account.moved) {
|
||||
|
@ -69,6 +71,8 @@ export function importFetchedStatuses(statuses) {
|
|||
const polls = [];
|
||||
|
||||
function processStatus(status) {
|
||||
if (!status.account.id) return;
|
||||
|
||||
const normalOldStatus = getState().getIn(['statuses', status.id]);
|
||||
const expandSpoilers = getSettings(getState()).get('expandSpoilers');
|
||||
|
||||
|
|
|
@ -10,7 +10,11 @@ import {
|
|||
} from './importer';
|
||||
import { getSettings, saveSettings } from './settings';
|
||||
import { defineMessages } from 'react-intl';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import {
|
||||
List as ImmutableList,
|
||||
Map as ImmutableMap,
|
||||
OrderedMap as ImmutableOrderedMap,
|
||||
} from 'immutable';
|
||||
import { unescapeHTML } from '../utils/html';
|
||||
import { getFilters, regexFromFilters } from '../selectors';
|
||||
|
||||
|
@ -121,7 +125,7 @@ export function updateNotificationsQueue(notification, intlMessages, intlLocale,
|
|||
|
||||
export function dequeueNotifications() {
|
||||
return (dispatch, getState) => {
|
||||
const queuedNotifications = getState().getIn(['notifications', 'queuedNotifications'], ImmutableList());
|
||||
const queuedNotifications = getState().getIn(['notifications', 'queuedNotifications'], ImmutableOrderedMap());
|
||||
const totalQueuedNotificationsCount = getState().getIn(['notifications', 'totalQueuedNotificationsCount'], 0);
|
||||
|
||||
if (totalQueuedNotificationsCount === 0) {
|
||||
|
@ -252,9 +256,12 @@ export function setFilter(filterType) {
|
|||
|
||||
export function markReadNotifications() {
|
||||
return (dispatch, getState) => {
|
||||
if (!getState().get('me')) return;
|
||||
const topNotification = parseInt(getState().getIn(['notifications', 'items', 0, 'id']));
|
||||
const lastRead = getState().getIn(['notifications', 'lastRead']);
|
||||
const state = getState();
|
||||
if (!state.get('me')) return;
|
||||
|
||||
const topNotification = state.getIn(['notifications', 'items'], ImmutableOrderedMap()).first(ImmutableMap()).get('id');
|
||||
const lastRead = state.getIn(['notifications', 'lastRead']);
|
||||
|
||||
if (!(topNotification && topNotification > lastRead)) return;
|
||||
|
||||
dispatch({
|
||||
|
|
|
@ -25,6 +25,17 @@ export function initReport(account, status) {
|
|||
};
|
||||
};
|
||||
|
||||
export function initReportById(accountId) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: REPORT_INIT,
|
||||
account: getState().getIn(['accounts', accountId]),
|
||||
});
|
||||
|
||||
dispatch(openModal('REPORT'));
|
||||
};
|
||||
};
|
||||
|
||||
export function cancelReport() {
|
||||
return {
|
||||
type: REPORT_CANCEL,
|
||||
|
|
|
@ -32,6 +32,7 @@ const defaultSettings = ImmutableMap({
|
|||
chats: ImmutableMap({
|
||||
panes: ImmutableList(),
|
||||
mainWindow: 'minimized',
|
||||
sound: true,
|
||||
}),
|
||||
|
||||
home: ImmutableMap({
|
||||
|
|
|
@ -219,7 +219,6 @@ export function fetchContextSuccess(id, ancestors, descendants) {
|
|||
id,
|
||||
ancestors,
|
||||
descendants,
|
||||
statuses: ancestors.concat(descendants),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -55,7 +55,17 @@ export function connectTimelineStream(timelineId, path, pollingRefresh = null, a
|
|||
dispatch(fetchFilters());
|
||||
break;
|
||||
case 'pleroma:chat_update':
|
||||
dispatch({ type: STREAMING_CHAT_UPDATE, chat: JSON.parse(data.payload), me: getState().get('me') });
|
||||
dispatch((dispatch, getState) => {
|
||||
const chat = JSON.parse(data.payload);
|
||||
const messageOwned = !(chat.last_message && chat.last_message.account_id !== getState().get('me'));
|
||||
|
||||
dispatch({
|
||||
type: STREAMING_CHAT_UPDATE,
|
||||
chat,
|
||||
// Only play sounds for recipient messages
|
||||
meta: !messageOwned && getSettings(getState()).getIn(['chats', 'sound']) && { sound: 'chat' },
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -6,6 +6,7 @@ exports[`<DisplayName /> renders display name + account name 1`] = `
|
|||
>
|
||||
<span
|
||||
className="hover-ref-wrapper"
|
||||
onClick={[Function]}
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
>
|
||||
|
|
|
@ -36,6 +36,7 @@ class SoapboxHelmet extends React.Component {
|
|||
<Helmet
|
||||
titleTemplate={this.addCounter(`%s | ${siteTitle}`)}
|
||||
defaultTitle={this.addCounter(siteTitle)}
|
||||
defer={false}
|
||||
>
|
||||
{children}
|
||||
</Helmet>
|
||||
|
|
|
@ -26,6 +26,13 @@ const handleMouseLeave = (dispatch) => {
|
|||
};
|
||||
};
|
||||
|
||||
const handleClick = (dispatch) => {
|
||||
return e => {
|
||||
showProfileHoverCard.cancel();
|
||||
dispatch(closeProfileHoverCard(true));
|
||||
};
|
||||
};
|
||||
|
||||
export const HoverRefWrapper = ({ accountId, children, inline }) => {
|
||||
const dispatch = useDispatch();
|
||||
const ref = useRef();
|
||||
|
@ -37,6 +44,7 @@ export const HoverRefWrapper = ({ accountId, children, inline }) => {
|
|||
className='hover-ref-wrapper'
|
||||
onMouseEnter={handleMouseEnter(dispatch, ref, accountId)}
|
||||
onMouseLeave={handleMouseLeave(dispatch)}
|
||||
onClick={handleClick(dispatch)}
|
||||
>
|
||||
{children}
|
||||
</Elem>
|
||||
|
|
|
@ -59,6 +59,7 @@ const mapStateToProps = (state) => {
|
|||
locale: validLocale(locale) ? locale : 'en',
|
||||
themeCss: generateThemeCss(soapboxConfig.get('brandColor')),
|
||||
themeMode: settings.get('themeMode'),
|
||||
halloween: settings.get('halloween'),
|
||||
customCss: soapboxConfig.get('customCss'),
|
||||
};
|
||||
};
|
||||
|
@ -77,6 +78,7 @@ class SoapboxMount extends React.PureComponent {
|
|||
themeCss: PropTypes.string,
|
||||
themeMode: PropTypes.string,
|
||||
customCss: ImmutablePropTypes.list,
|
||||
halloween: PropTypes.bool,
|
||||
dispatch: PropTypes.func,
|
||||
};
|
||||
|
||||
|
@ -122,6 +124,7 @@ class SoapboxMount extends React.PureComponent {
|
|||
'no-reduce-motion': !this.props.reduceMotion,
|
||||
'dyslexic': this.props.dyslexicFont,
|
||||
'demetricator': this.props.demetricator,
|
||||
'halloween': this.props.halloween,
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
|
@ -20,17 +20,18 @@ class LoginPage extends ImmutablePureComponent {
|
|||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
}
|
||||
|
||||
state = {
|
||||
isLoading: false,
|
||||
mfa_auth_needed: false,
|
||||
mfa_token: '',
|
||||
}
|
||||
|
||||
getFormData = (form) => {
|
||||
return Object.fromEntries(
|
||||
Array.from(form).map(i => [i.name, i.value])
|
||||
);
|
||||
}
|
||||
|
||||
state = {
|
||||
mfa_auth_needed: false,
|
||||
mfa_token: '',
|
||||
}
|
||||
|
||||
handleSubmit = (event) => {
|
||||
const { dispatch } = this.props;
|
||||
const { username, password } = this.getFormData(event.target);
|
||||
|
@ -47,8 +48,8 @@ class LoginPage extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { me, isLoading } = this.props;
|
||||
const { mfa_auth_needed, mfa_token } = this.state;
|
||||
const { me } = this.props;
|
||||
const { isLoading, mfa_auth_needed, mfa_token } = this.state;
|
||||
if (me) return <Redirect to='/' />;
|
||||
|
||||
if (mfa_auth_needed) return <OtpAuthForm mfa_token={mfa_token} />;
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import { changeSetting, getSettings } from 'soapbox/actions/settings';
|
||||
import SettingToggle from 'soapbox/features/notifications/components/setting_toggle';
|
||||
|
||||
const messages = defineMessages({
|
||||
switchToOn: { id: 'chats.audio_toggle_on', defaultMessage: 'Audio notification on' },
|
||||
switchToOff: { id: 'chats.audio_toggle_off', defaultMessage: 'Audio notification off' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
settings: getSettings(state),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
toggleAudio(setting) {
|
||||
dispatch(changeSetting(['chats', 'sound'], setting));
|
||||
},
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class AudioToggle extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
toggleAudio: PropTypes.func,
|
||||
showLabel: PropTypes.bool,
|
||||
};
|
||||
|
||||
handleToggleAudio = () => {
|
||||
this.props.toggleAudio(this.props.settings.getIn(['chats', 'sound']) === true ? false : true);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl, settings, showLabel } = this.props;
|
||||
let toggle = (
|
||||
<SettingToggle settings={settings} settingPath={['chats', 'sound']} onChange={this.handleToggleAudio} icons={{ checked: <Icon id='volume-up' />, unchecked: <Icon id='volume-off' /> }} ariaLabel={settings.get('chats', 'sound') === true ? intl.formatMessage(messages.switchToOff) : intl.formatMessage(messages.switchToOn)} />
|
||||
);
|
||||
|
||||
if (showLabel) {
|
||||
toggle = (
|
||||
<SettingToggle settings={settings} settingPath={['chats', 'sound']} onChange={this.handleToggleAudio} icons={{ checked: <Icon id='volume-up' />, unchecked: <Icon id='volume-off' /> }} label={settings.get('chats', 'sound') === true ? intl.formatMessage(messages.switchToOff) : intl.formatMessage(messages.switchToOn)} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='audio-toggle react-toggle--mini'>
|
||||
{toggle}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -18,6 +18,7 @@ import IconButton from 'soapbox/components/icon_button';
|
|||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'chat_box.input.placeholder', defaultMessage: 'Send a message…' },
|
||||
send: { id: 'chat_box.actions.send', defaultMessage: 'Send' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, { chatId }) => ({
|
||||
|
@ -94,6 +95,7 @@ class ChatBox extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
handleKeyDown = (e) => {
|
||||
this.markRead();
|
||||
if (e.key === 'Enter' && e.shiftKey) {
|
||||
this.insertLine();
|
||||
e.preventDefault();
|
||||
|
@ -122,17 +124,6 @@ class ChatBox extends ImmutablePureComponent {
|
|||
onSetInputRef(el);
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const markReadConditions = [
|
||||
() => this.props.chat !== undefined,
|
||||
() => document.activeElement === this.inputElem,
|
||||
() => this.props.chat.get('unread') > 0,
|
||||
];
|
||||
|
||||
if (markReadConditions.every(c => c() === true))
|
||||
this.markRead();
|
||||
}
|
||||
|
||||
handleRemoveFile = (e) => {
|
||||
this.setState({ attachment: undefined, resetFileKey: fileKeyGen() });
|
||||
}
|
||||
|
@ -174,11 +165,17 @@ class ChatBox extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
renderActionButton = () => {
|
||||
const { intl } = this.props;
|
||||
const { resetFileKey } = this.state;
|
||||
|
||||
return this.canSubmit() ? (
|
||||
<div className='chat-box__send'>
|
||||
<IconButton icon='send' size={16} onClick={this.sendMessage} />
|
||||
<IconButton
|
||||
icon='send'
|
||||
title={intl.formatMessage(messages.send)}
|
||||
size={16}
|
||||
onClick={this.sendMessage}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<UploadButton onSelectFile={this.handleFiles} resetFileKey={resetFileKey} />
|
||||
|
|
|
@ -2,16 +2,37 @@ import React from 'react';
|
|||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import { fetchChatMessages } from 'soapbox/actions/chats';
|
||||
import { fetchChatMessages, deleteChatMessage } from 'soapbox/actions/chats';
|
||||
import emojify from 'soapbox/features/emoji/emoji';
|
||||
import classNames from 'classnames';
|
||||
import { openModal } from 'soapbox/actions/modal';
|
||||
import { escape, throttle } from 'lodash';
|
||||
import { MediaGallery } from 'soapbox/features/ui/util/async-components';
|
||||
import Bundle from 'soapbox/features/ui/components/bundle';
|
||||
import DropdownMenuContainer from 'soapbox/containers/dropdown_menu_container';
|
||||
import { initReportById } from 'soapbox/actions/reports';
|
||||
|
||||
const messages = defineMessages({
|
||||
today: { id: 'chats.dividers.today', defaultMessage: 'Today' },
|
||||
more: { id: 'chats.actions.more', defaultMessage: 'More' },
|
||||
delete: { id: 'chats.actions.delete', defaultMessage: 'Delete message' },
|
||||
report: { id: 'chats.actions.report', defaultMessage: 'Report user' },
|
||||
});
|
||||
|
||||
const timeChange = (prev, curr) => {
|
||||
const prevDate = new Date(prev.get('created_at')).getDate();
|
||||
const currDate = new Date(curr.get('created_at')).getDate();
|
||||
const nowDate = new Date().getDate();
|
||||
|
||||
if (prevDate !== currDate) {
|
||||
return currDate === nowDate ? 'today' : 'date';
|
||||
};
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const makeEmojiMap = record => record.get('emojis', ImmutableList()).reduce((map, emoji) => {
|
||||
return map.set(`:${emoji.get('shortcode')}:`, emoji);
|
||||
|
@ -89,11 +110,16 @@ class ChatMessageList extends ImmutablePureComponent {
|
|||
return scrollBottom < elem.offsetHeight * 1.5;
|
||||
}
|
||||
|
||||
handleResize = (e) => {
|
||||
if (this.isNearBottom()) this.scrollToBottom();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { dispatch, chatId } = this.props;
|
||||
dispatch(fetchChatMessages(chatId));
|
||||
|
||||
this.node.addEventListener('scroll', this.handleScroll);
|
||||
window.addEventListener('resize', this.handleResize);
|
||||
this.scrollToBottom();
|
||||
}
|
||||
|
||||
|
@ -125,6 +151,7 @@ class ChatMessageList extends ImmutablePureComponent {
|
|||
|
||||
componentWillUnmount() {
|
||||
this.node.removeEventListener('scroll', this.handleScroll);
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
}
|
||||
|
||||
handleLoadMore = () => {
|
||||
|
@ -176,7 +203,8 @@ class ChatMessageList extends ImmutablePureComponent {
|
|||
parseContent = chatMessage => {
|
||||
const content = chatMessage.get('content') || '';
|
||||
const pending = chatMessage.get('pending', false);
|
||||
const formatted = pending ? this.parsePendingContent(content) : content;
|
||||
const deleting = chatMessage.get('deleting', false);
|
||||
const formatted = (pending && !deleting) ? this.parsePendingContent(content) : content;
|
||||
const emojiMap = makeEmojiMap(chatMessage);
|
||||
return emojify(formatted, emojiMap.toJS());
|
||||
}
|
||||
|
@ -185,12 +213,30 @@ class ChatMessageList extends ImmutablePureComponent {
|
|||
this.node = c;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { chatMessages, me } = this.props;
|
||||
renderDivider = (key, text) => (
|
||||
<div className='chat-messages__divider' key={key}>{text}</div>
|
||||
)
|
||||
|
||||
handleDeleteMessage = (chatId, messageId) => {
|
||||
return () => {
|
||||
this.props.dispatch(deleteChatMessage(chatId, messageId));
|
||||
};
|
||||
}
|
||||
|
||||
handleReportUser = (userId) => {
|
||||
return () => {
|
||||
this.props.dispatch(initReportById(userId));
|
||||
};
|
||||
}
|
||||
|
||||
renderMessage = (chatMessage) => {
|
||||
const { me, intl } = this.props;
|
||||
const menu = [
|
||||
{ text: intl.formatMessage(messages.delete), action: this.handleDeleteMessage(chatMessage.get('chat_id'), chatMessage.get('id')) },
|
||||
{ text: intl.formatMessage(messages.report), action: this.handleReportUser(chatMessage.get('account_id')) },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className='chat-messages' ref={this.setRef}>
|
||||
{chatMessages.map(chatMessage => (
|
||||
<div
|
||||
className={classNames('chat-message', {
|
||||
'chat-message--me': chatMessage.get('account_id') === me,
|
||||
|
@ -202,15 +248,50 @@ class ChatMessageList extends ImmutablePureComponent {
|
|||
title={this.getFormattedTimestamp(chatMessage)}
|
||||
className='chat-message__bubble'
|
||||
ref={this.setBubbleRef}
|
||||
tabIndex={0}
|
||||
>
|
||||
{this.maybeRenderMedia(chatMessage)}
|
||||
<span
|
||||
className='chat-message__content'
|
||||
dangerouslySetInnerHTML={{ __html: this.parseContent(chatMessage) }}
|
||||
/>
|
||||
<div className='chat-message__menu'>
|
||||
<DropdownMenuContainer
|
||||
items={menu}
|
||||
icon='ellipsis-h'
|
||||
size={18}
|
||||
direction='top'
|
||||
title={intl.formatMessage(messages.more)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { chatMessages, intl } = this.props;
|
||||
|
||||
return (
|
||||
<div className='chat-messages' ref={this.setRef}>
|
||||
{chatMessages.reduce((acc, curr, idx) => {
|
||||
const lastMessage = chatMessages.get(idx-1);
|
||||
|
||||
if (lastMessage) {
|
||||
const key = `${curr.get('id')}_divider`;
|
||||
switch(timeChange(lastMessage, curr)) {
|
||||
case 'today':
|
||||
acc.push(this.renderDivider(key, intl.formatMessage(messages.today)));
|
||||
break;
|
||||
case 'date':
|
||||
acc.push(this.renderDivider(key, new Date(curr.get('created_at')).toDateString()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
acc.push(this.renderMessage(curr));
|
||||
return acc;
|
||||
}, [])}
|
||||
<div style={{ float: 'left', clear: 'both' }} ref={this.setMessageEndRef} />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -11,6 +11,7 @@ import { makeGetChat } from 'soapbox/selectors';
|
|||
import { openChat, toggleMainWindow } from 'soapbox/actions/chats';
|
||||
import ChatWindow from './chat_window';
|
||||
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
||||
import AudioToggle from 'soapbox/features/chats/components/audio_toggle';
|
||||
|
||||
const addChatsToPanes = (state, panesData) => {
|
||||
const getChat = makeGetChat();
|
||||
|
@ -62,6 +63,7 @@ class ChatPanes extends ImmutablePureComponent {
|
|||
<button className='pane__title' onClick={this.handleMainWindowToggle}>
|
||||
<FormattedMessage id='chat_panels.main_window.title' defaultMessage='Chats' />
|
||||
</button>
|
||||
<AudioToggle />
|
||||
</div>
|
||||
<div className='pane__content'>
|
||||
<ChatList
|
||||
|
|
|
@ -4,6 +4,7 @@ import Column from '../../components/column';
|
|||
import ColumnHeader from '../../components/column_header';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ChatList from './components/chat_list';
|
||||
import AudioToggle from 'soapbox/features/chats/components/audio_toggle';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.chats', defaultMessage: 'Chats' },
|
||||
|
@ -33,6 +34,7 @@ class ChatIndex extends React.PureComponent {
|
|||
icon='comment'
|
||||
title={intl.formatMessage(messages.title)}
|
||||
/>
|
||||
<div className='column__switch'><AudioToggle /></div>
|
||||
|
||||
<ChatList
|
||||
onClickChat={this.handleClickChat}
|
||||
|
|
|
@ -3,14 +3,10 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
|||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { SketchPicker } from 'react-color';
|
||||
import Overlay from 'react-overlays/lib/Overlay';
|
||||
import { isMobile } from '../../is_mobile';
|
||||
import detectPassiveEvents from 'detect-passive-events';
|
||||
import FontIconPicker from '@fonticonpicker/react-fonticonpicker';
|
||||
import forkAwesomeIcons from './forkawesome.json';
|
||||
|
||||
const FormPropTypes = {
|
||||
export const FormPropTypes = {
|
||||
label: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.object,
|
||||
|
@ -18,8 +14,6 @@ const FormPropTypes = {
|
|||
]),
|
||||
};
|
||||
|
||||
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false;
|
||||
|
||||
export const InputContainer = (props) => {
|
||||
const containerClass = classNames('input', {
|
||||
'with_label': props.label,
|
||||
|
@ -226,98 +220,6 @@ export class IconPicker extends ImmutablePureComponent {
|
|||
|
||||
}
|
||||
|
||||
export class ColorPicker extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
style: PropTypes.object,
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func,
|
||||
}
|
||||
|
||||
handleDocumentClick = e => {
|
||||
if (this.node && !this.node.contains(e.target)) {
|
||||
this.props.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener('click', this.handleDocumentClick, false);
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('click', this.handleDocumentClick, false);
|
||||
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { style, value, onChange } = this.props;
|
||||
let margin_left_picker = isMobile(window.innerWidth) ? '20px' : '12px';
|
||||
|
||||
return (
|
||||
<div id='SketchPickerContainer' ref={this.setRef} style={{ ...style, marginLeft: margin_left_picker, position: 'absolute', zIndex: 1000 }}>
|
||||
<SketchPicker color={value} disableAlpha onChange={onChange} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ColorWithPicker extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
buttonId: PropTypes.string.isRequired,
|
||||
label: FormPropTypes.label,
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
onToggle = (e) => {
|
||||
if (!e.key || e.key === 'Enter') {
|
||||
if (this.state.active) {
|
||||
this.onHidePicker();
|
||||
} else {
|
||||
this.onShowPicker(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state = {
|
||||
active: false,
|
||||
placement: null,
|
||||
}
|
||||
|
||||
onHidePicker = () => {
|
||||
this.setState({ active: false });
|
||||
}
|
||||
|
||||
onShowPicker = ({ target }) => {
|
||||
this.setState({ active: true });
|
||||
this.setState({ placement: isMobile(window.innerWidth) ? 'bottom' : 'right' });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { buttonId, label, value, onChange } = this.props;
|
||||
const { active, placement } = this.state;
|
||||
|
||||
return (
|
||||
<div className='label_input__color'>
|
||||
<label>{label}</label>
|
||||
<div id={buttonId} className='color-swatch' role='presentation' style={{ background: value }} title={value} value={value} onClick={this.onToggle} />
|
||||
<Overlay show={active} placement={placement} target={this}>
|
||||
<ColorPicker value={value} onChange={onChange} onClose={this.onHidePicker} />
|
||||
</Overlay>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class RadioItem extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
|
|
|
@ -30,7 +30,7 @@ const getNotifications = createSelector([
|
|||
state => getSettings(state).getIn(['notifications', 'quickFilter', 'show']),
|
||||
state => getSettings(state).getIn(['notifications', 'quickFilter', 'active']),
|
||||
state => ImmutableList(getSettings(state).getIn(['notifications', 'shows']).filter(item => !item).keys()),
|
||||
state => state.getIn(['notifications', 'items']),
|
||||
state => state.getIn(['notifications', 'items']).toList(),
|
||||
], (showFilterBar, allowedType, excludedTypes, notifications) => {
|
||||
if (!showFilterBar || allowedType === 'all') {
|
||||
// used if user changed the notification settings after loading the notifications from the server
|
||||
|
|
|
@ -185,6 +185,11 @@ class Preferences extends ImmutablePureComponent {
|
|||
path={['dyslexicFont']}
|
||||
/>
|
||||
</div>
|
||||
<SettingsCheckbox
|
||||
label={<FormattedMessage id='preferences.fields.halloween_label' defaultMessage='Halloween mode' />}
|
||||
hint={<FormattedMessage id='preferences.hints.halloween' defaultMessage='Beware: SPOOKY! Supports light/dark toggle.' />}
|
||||
path={['halloween']}
|
||||
/>
|
||||
<SettingsCheckbox
|
||||
label={<FormattedMessage id='preferences.fields.demetricator_label' defaultMessage='Use Demetricator' />}
|
||||
hint={<FormattedMessage id='preferences.hints.demetricator' defaultMessage='Decrease social media anxiety by hiding all numbers from the site.' />}
|
||||
|
|
|
@ -6,14 +6,18 @@ import { Link } from 'react-router-dom';
|
|||
import LoginForm from 'soapbox/features/auth_login/components/login_form';
|
||||
import SiteLogo from './site_logo';
|
||||
import SoapboxPropTypes from 'soapbox/utils/soapbox_prop_types';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { logIn } from 'soapbox/actions/auth';
|
||||
import { fetchMe } from 'soapbox/actions/me';
|
||||
import PropTypes from 'prop-types';
|
||||
import OtpAuthForm from 'soapbox/features/auth_login/components/otp_auth_form';
|
||||
import IconButton from 'soapbox/components/icon_button';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
const messages = defineMessages({
|
||||
home: { id: 'header.home.label', defaultMessage: 'Home' },
|
||||
about: { id: 'header.about.label', defaultMessage: 'About' },
|
||||
backTo: { id: 'header.back_to.label', defaultMessage: 'Back to {siteTitle}' },
|
||||
login: { id: 'header.login.label', defaultMessage: 'Log in' },
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
});
|
||||
|
||||
|
@ -32,6 +36,12 @@ class Header extends ImmutablePureComponent {
|
|||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
}
|
||||
|
||||
state = {
|
||||
isLoading: false,
|
||||
mfa_auth_needed: false,
|
||||
mfa_token: '',
|
||||
}
|
||||
|
||||
getFormData = (form) => {
|
||||
return Object.fromEntries(
|
||||
Array.from(form).map(i => [i.name, i.value])
|
||||
|
@ -64,16 +74,12 @@ class Header extends ImmutablePureComponent {
|
|||
static propTypes = {
|
||||
me: SoapboxPropTypes.me,
|
||||
instance: ImmutablePropTypes.map,
|
||||
}
|
||||
|
||||
state = {
|
||||
mfa_auth_needed: false,
|
||||
mfa_token: '',
|
||||
intl: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { me, instance, isLoading, intl } = this.props;
|
||||
const { mfa_auth_needed, mfa_token } = this.state;
|
||||
const { me, instance, intl } = this.props;
|
||||
const { isLoading, mfa_auth_needed, mfa_token } = this.state;
|
||||
|
||||
return (
|
||||
<nav className='header'>
|
||||
|
@ -90,21 +96,21 @@ class Header extends ImmutablePureComponent {
|
|||
<Link className='brand' to='/'>
|
||||
<SiteLogo />
|
||||
</Link>
|
||||
<Link className='nav-link optional' to='/'>Home</Link>
|
||||
<Link className='nav-link' to='/about'>About</Link>
|
||||
<Link className='nav-link optional' to='/'>{intl.formatMessage(messages.home)}</Link>
|
||||
<Link className='nav-link' to='/about'>{intl.formatMessage(messages.about)}</Link>
|
||||
</div>
|
||||
<div className='nav-center' />
|
||||
<div className='nav-right'>
|
||||
<div className='hidden-sm'>
|
||||
{me
|
||||
? <Link className='nav-link nav-button webapp-btn' to='/'>Back to {instance.get('title')}</Link>
|
||||
? <Link className='nav-link nav-button webapp-btn' to='/'>{intl.formatMessage(messages.backTo, { siteTitle: instance.get('title') })}</Link>
|
||||
: <LoginForm handleSubmit={this.handleSubmit} isLoading={isLoading} />
|
||||
}
|
||||
</div>
|
||||
<div className='visible-sm'>
|
||||
{me
|
||||
? <Link className='nav-link nav-button webapp-btn' to='/'>Back to {instance.get('title')}</Link>
|
||||
: <Link className='nav-link nav-button webapp-btn' to='/auth/sign_in'>Log in</Link>
|
||||
? <Link className='nav-link nav-button webapp-btn' to='/'>{intl.formatMessage(messages.backTo, { siteTitle: instance.get('title') })}</Link>
|
||||
: <Link className='nav-link nav-button webapp-btn' to='/auth/sign_in'>{intl.formatMessage(messages.login)}</Link>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,15 +12,19 @@ import {
|
|||
Checkbox,
|
||||
FileChooser,
|
||||
SimpleTextarea,
|
||||
ColorWithPicker,
|
||||
FileChooserLogo,
|
||||
IconPicker,
|
||||
FormPropTypes,
|
||||
} from 'soapbox/features/forms';
|
||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
|
||||
import { updateAdminConfig } from 'soapbox/actions/admin';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import { defaultConfig } from 'soapbox/actions/soapbox';
|
||||
import { uploadMedia } from 'soapbox/actions/media';
|
||||
import { SketchPicker } from 'react-color';
|
||||
import Overlay from 'react-overlays/lib/Overlay';
|
||||
import { isMobile } from 'soapbox/is_mobile';
|
||||
import detectPassiveEvents from 'detect-passive-events';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.soapbox_config', defaultMessage: 'Soapbox config' },
|
||||
|
@ -35,6 +39,8 @@ const messages = defineMessages({
|
|||
rawJSONHint: { id: 'soapbox_config.raw_json_hint', defaultMessage: 'Advanced: Edit the settings data directly.' },
|
||||
});
|
||||
|
||||
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false;
|
||||
|
||||
const templates = {
|
||||
promoPanelItem: ImmutableMap({ icon: '', text: '', url: '' }),
|
||||
footerItem: ImmutableMap({ title: '', url: '' }),
|
||||
|
@ -364,3 +370,95 @@ class SoapboxConfig extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
class ColorPicker extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
style: PropTypes.object,
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func,
|
||||
}
|
||||
|
||||
handleDocumentClick = e => {
|
||||
if (this.node && !this.node.contains(e.target)) {
|
||||
this.props.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener('click', this.handleDocumentClick, false);
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('click', this.handleDocumentClick, false);
|
||||
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { style, value, onChange } = this.props;
|
||||
let margin_left_picker = isMobile(window.innerWidth) ? '20px' : '12px';
|
||||
|
||||
return (
|
||||
<div id='SketchPickerContainer' ref={this.setRef} style={{ ...style, marginLeft: margin_left_picker, position: 'absolute', zIndex: 1000 }}>
|
||||
<SketchPicker color={value} disableAlpha onChange={onChange} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ColorWithPicker extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
buttonId: PropTypes.string.isRequired,
|
||||
label: FormPropTypes.label,
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
onToggle = (e) => {
|
||||
if (!e.key || e.key === 'Enter') {
|
||||
if (this.state.active) {
|
||||
this.onHidePicker();
|
||||
} else {
|
||||
this.onShowPicker(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state = {
|
||||
active: false,
|
||||
placement: null,
|
||||
}
|
||||
|
||||
onHidePicker = () => {
|
||||
this.setState({ active: false });
|
||||
}
|
||||
|
||||
onShowPicker = ({ target }) => {
|
||||
this.setState({ active: true });
|
||||
this.setState({ placement: isMobile(window.innerWidth) ? 'bottom' : 'right' });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { buttonId, label, value, onChange } = this.props;
|
||||
const { active, placement } = this.state;
|
||||
|
||||
return (
|
||||
<div className='label_input__color'>
|
||||
<label>{label}</label>
|
||||
<div id={buttonId} className='color-swatch' role='presentation' style={{ background: value }} title={value} value={value} onClick={this.onToggle} />
|
||||
<Overlay show={active} placement={placement} target={this}>
|
||||
<ColorPicker value={value} onChange={onChange} onClose={this.onHidePicker} />
|
||||
</Overlay>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -56,21 +56,21 @@ class UserPanel extends ImmutablePureComponent {
|
|||
|
||||
<div className='user-panel__stats-block'>
|
||||
|
||||
{account.get('statuses_count') && <div className='user-panel-stats-item'>
|
||||
{account.get('statuses_count') >= 0 && <div className='user-panel-stats-item'>
|
||||
<Link to={`/@${account.get('acct')}`} title={intl.formatNumber(account.get('statuses_count'))}>
|
||||
<strong className='user-panel-stats-item__value'>{shortNumberFormat(account.get('statuses_count'))}</strong>
|
||||
<span className='user-panel-stats-item__label'><FormattedMessage className='user-panel-stats-item__label' id='account.posts' defaultMessage='Posts' /></span>
|
||||
</Link>
|
||||
</div>}
|
||||
|
||||
{account.get('followers_count') && <div className='user-panel-stats-item'>
|
||||
{account.get('followers_count') >= 0 && <div className='user-panel-stats-item'>
|
||||
<Link to={`/@${account.get('acct')}/followers`} title={intl.formatNumber(account.get('followers_count'))}>
|
||||
<strong className='user-panel-stats-item__value'>{shortNumberFormat(account.get('followers_count'))}</strong>
|
||||
<span className='user-panel-stats-item__label'><FormattedMessage id='account.followers' defaultMessage='Followers' /></span>
|
||||
</Link>
|
||||
</div>}
|
||||
|
||||
{account.get('following_count') && <div className='user-panel-stats-item'>
|
||||
{account.get('following_count') >= 0 && <div className='user-panel-stats-item'>
|
||||
<Link to={`/@${account.get('acct')}/following`} title={intl.formatNumber(account.get('following_count'))}>
|
||||
<strong className='user-panel-stats-item__value'>{shortNumberFormat(account.get('following_count'))}</strong>
|
||||
<span className='user-panel-stats-item__label'><FormattedMessage className='user-panel-stats-item__label' id='account.follows' defaultMessage='Follows' /></span>
|
||||
|
|
|
@ -36,6 +36,16 @@ export default function soundsMiddleware() {
|
|||
type: 'audio/mpeg',
|
||||
},
|
||||
]),
|
||||
chat: createAudio([
|
||||
{
|
||||
src: '/sounds/chat.oga',
|
||||
type: 'audio/ogg',
|
||||
},
|
||||
{
|
||||
src: '/sounds/chat.mp3',
|
||||
type: 'audio/mpeg',
|
||||
},
|
||||
]),
|
||||
};
|
||||
|
||||
return () => next => action => {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import reducer from '../contexts';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
import { CONTEXT_FETCH_SUCCESS } from 'soapbox/actions/statuses';
|
||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||
import context1 from 'soapbox/__fixtures__/context_1.json';
|
||||
import context2 from 'soapbox/__fixtures__/context_2.json';
|
||||
|
||||
describe('contexts reducer', () => {
|
||||
it('should return the initial state', () => {
|
||||
|
@ -8,4 +11,34 @@ describe('contexts reducer', () => {
|
|||
replies: ImmutableMap(),
|
||||
}));
|
||||
});
|
||||
|
||||
it('should support rendering a complete tree', () => {
|
||||
// https://gitlab.com/soapbox-pub/soapbox-fe/-/issues/422
|
||||
let result;
|
||||
result = reducer(result, { type: CONTEXT_FETCH_SUCCESS, id: '9zIH8WYwtnUx4yDzUm', ancestors: context1.ancestors, descendants: context1.descendants });
|
||||
result = reducer(result, { type: CONTEXT_FETCH_SUCCESS, id: '9zIH7PUdhK3Ircg4hM', ancestors: context2.ancestors, descendants: context2.descendants });
|
||||
|
||||
expect(result).toEqual(ImmutableMap({
|
||||
inReplyTos: ImmutableMap({
|
||||
'9zIH7PUdhK3Ircg4hM': '9zIH6kDXA10YqhMKqO',
|
||||
'9zIH7mMGgc1RmJwDLM': '9zIH6kDXA10YqhMKqO',
|
||||
'9zIH9GTCDWEFSRt2um': '9zIH7PUdhK3Ircg4hM',
|
||||
'9zIH9fhaP9atiJoOJc': '9zIH8WYwtnUx4yDzUm',
|
||||
'9zIH8WYwtnUx4yDzUm': '9zIH7PUdhK3Ircg4hM',
|
||||
}),
|
||||
replies: ImmutableMap({
|
||||
'9zIH6kDXA10YqhMKqO': ImmutableOrderedSet([
|
||||
'9zIH7PUdhK3Ircg4hM',
|
||||
'9zIH7mMGgc1RmJwDLM',
|
||||
]),
|
||||
'9zIH7PUdhK3Ircg4hM': ImmutableOrderedSet([
|
||||
'9zIH8WYwtnUx4yDzUm',
|
||||
'9zIH9GTCDWEFSRt2um',
|
||||
]),
|
||||
'9zIH8WYwtnUx4yDzUm': ImmutableOrderedSet([
|
||||
'9zIH9fhaP9atiJoOJc',
|
||||
]),
|
||||
}),
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
import * as actions from 'soapbox/actions/notifications';
|
||||
import reducer from '../notifications';
|
||||
import notifications from 'soapbox/__fixtures__/notifications.json';
|
||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import { Map as ImmutableMap, OrderedMap as ImmutableOrderedMap } from 'immutable';
|
||||
import { take } from 'lodash';
|
||||
import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS } from 'soapbox/actions/accounts';
|
||||
import notification from 'soapbox/__fixtures__/notification.json';
|
||||
import intlMessages from 'soapbox/__fixtures__/intlMessages.json';
|
||||
import relationship from 'soapbox/__fixtures__/relationship.json';
|
||||
import { TIMELINE_DELETE, TIMELINE_DISCONNECT } from 'soapbox/actions/timelines';
|
||||
import { TIMELINE_DELETE } from 'soapbox/actions/timelines';
|
||||
|
||||
describe('notifications reducer', () => {
|
||||
it('should return the initial state', () => {
|
||||
expect(reducer(undefined, {})).toEqual(ImmutableMap({
|
||||
items: ImmutableList(),
|
||||
items: ImmutableOrderedMap(),
|
||||
hasMore: true,
|
||||
top: false,
|
||||
unread: 0,
|
||||
isLoading: false,
|
||||
queuedNotifications: ImmutableList(),
|
||||
queuedNotifications: ImmutableOrderedMap(),
|
||||
totalQueuedNotificationsCount: 0,
|
||||
lastRead: -1,
|
||||
}));
|
||||
|
@ -32,8 +32,8 @@ describe('notifications reducer', () => {
|
|||
skipLoading: true,
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList([
|
||||
ImmutableMap({
|
||||
items: ImmutableOrderedMap([
|
||||
['10744', ImmutableMap({
|
||||
id: '10744',
|
||||
type: 'pleroma:emoji_reaction',
|
||||
account: '9vMAje101ngtjlMj7w',
|
||||
|
@ -42,8 +42,8 @@ describe('notifications reducer', () => {
|
|||
emoji: '😢',
|
||||
chat_message: undefined,
|
||||
is_seen: false,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10743', ImmutableMap({
|
||||
id: '10743',
|
||||
type: 'favourite',
|
||||
account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
|
@ -52,8 +52,8 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10741', ImmutableMap({
|
||||
id: '10741',
|
||||
type: 'favourite',
|
||||
account: '9v5cKMOPGqPcgfcWp6',
|
||||
|
@ -62,13 +62,13 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
})],
|
||||
]),
|
||||
hasMore: false,
|
||||
top: false,
|
||||
unread: 1,
|
||||
isLoading: false,
|
||||
queuedNotifications: ImmutableList(),
|
||||
queuedNotifications: ImmutableOrderedMap(),
|
||||
totalQueuedNotificationsCount: 0,
|
||||
lastRead: -1,
|
||||
}));
|
||||
|
@ -100,8 +100,8 @@ describe('notifications reducer', () => {
|
|||
|
||||
it('should handle NOTIFICATIONS_FILTER_SET', () => {
|
||||
const state = ImmutableMap({
|
||||
items: ImmutableList([
|
||||
ImmutableMap({
|
||||
items: ImmutableOrderedMap([
|
||||
['10744', ImmutableMap({
|
||||
id: '10744',
|
||||
type: 'pleroma:emoji_reaction',
|
||||
account: '9vMAje101ngtjlMj7w',
|
||||
|
@ -110,8 +110,8 @@ describe('notifications reducer', () => {
|
|||
emoji: '😢',
|
||||
chat_message: undefined,
|
||||
is_seen: false,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10743', ImmutableMap({
|
||||
id: '10743',
|
||||
type: 'favourite',
|
||||
account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
|
@ -120,8 +120,8 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10741', ImmutableMap({
|
||||
id: '10741',
|
||||
type: 'favourite',
|
||||
account: '9v5cKMOPGqPcgfcWp6',
|
||||
|
@ -130,13 +130,13 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
})],
|
||||
]),
|
||||
hasMore: false,
|
||||
top: false,
|
||||
unread: 1,
|
||||
isLoading: false,
|
||||
queuedNotifications: ImmutableList(),
|
||||
queuedNotifications: ImmutableOrderedMap(),
|
||||
totalQueuedNotificationsCount: 0,
|
||||
lastRead: -1,
|
||||
});
|
||||
|
@ -144,12 +144,12 @@ describe('notifications reducer', () => {
|
|||
type: actions.NOTIFICATIONS_FILTER_SET,
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList(),
|
||||
items: ImmutableOrderedMap(),
|
||||
hasMore: true,
|
||||
top: false,
|
||||
unread: 1,
|
||||
isLoading: false,
|
||||
queuedNotifications: ImmutableList(),
|
||||
queuedNotifications: ImmutableOrderedMap(),
|
||||
totalQueuedNotificationsCount: 0,
|
||||
lastRead: -1,
|
||||
}));
|
||||
|
@ -185,7 +185,7 @@ describe('notifications reducer', () => {
|
|||
|
||||
it('should handle NOTIFICATIONS_UPDATE, when top = false, increment unread', () => {
|
||||
const state = ImmutableMap({
|
||||
items: ImmutableList(),
|
||||
items: ImmutableOrderedMap(),
|
||||
top: false,
|
||||
unread: 1,
|
||||
});
|
||||
|
@ -194,8 +194,8 @@ describe('notifications reducer', () => {
|
|||
notification: notification,
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList([
|
||||
ImmutableMap({
|
||||
items: ImmutableOrderedMap([
|
||||
['10743', ImmutableMap({
|
||||
id: '10743',
|
||||
type: 'favourite',
|
||||
account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
|
@ -204,7 +204,7 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
})],
|
||||
]),
|
||||
top: false,
|
||||
unread: 2,
|
||||
|
@ -213,8 +213,8 @@ describe('notifications reducer', () => {
|
|||
|
||||
it('should handle NOTIFICATIONS_UPDATE_QUEUE', () => {
|
||||
const state = ImmutableMap({
|
||||
items: ImmutableList([]),
|
||||
queuedNotifications: ImmutableList([]),
|
||||
items: ImmutableOrderedMap(),
|
||||
queuedNotifications: ImmutableOrderedMap(),
|
||||
totalQueuedNotificationsCount: 0,
|
||||
});
|
||||
const action = {
|
||||
|
@ -224,19 +224,19 @@ describe('notifications reducer', () => {
|
|||
intlLocale: 'en',
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList([]),
|
||||
queuedNotifications: ImmutableList([{
|
||||
items: ImmutableOrderedMap(),
|
||||
queuedNotifications: ImmutableOrderedMap([[notification.id, {
|
||||
notification: notification,
|
||||
intlMessages: intlMessages,
|
||||
intlLocale: 'en',
|
||||
}]),
|
||||
}]]),
|
||||
totalQueuedNotificationsCount: 1,
|
||||
}));
|
||||
});
|
||||
|
||||
it('should handle NOTIFICATIONS_DEQUEUE', () => {
|
||||
const state = ImmutableMap({
|
||||
items: ImmutableList([]),
|
||||
items: ImmutableOrderedMap(),
|
||||
queuedNotifications: take(notifications, 1),
|
||||
totalQueuedNotificationsCount: 1,
|
||||
});
|
||||
|
@ -244,16 +244,16 @@ describe('notifications reducer', () => {
|
|||
type: actions.NOTIFICATIONS_DEQUEUE,
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList([]),
|
||||
queuedNotifications: ImmutableList([]),
|
||||
items: ImmutableOrderedMap(),
|
||||
queuedNotifications: ImmutableOrderedMap(),
|
||||
totalQueuedNotificationsCount: 0,
|
||||
}));
|
||||
});
|
||||
|
||||
it('should handle NOTIFICATIONS_EXPAND_SUCCESS with non-empty items and next set true', () => {
|
||||
const state = ImmutableMap({
|
||||
items: ImmutableList([
|
||||
ImmutableMap({
|
||||
items: ImmutableOrderedMap([
|
||||
['10734', ImmutableMap({
|
||||
id: '10734',
|
||||
type: 'pleroma:emoji_reaction',
|
||||
account: '9vMAje101ngtjlMj7w',
|
||||
|
@ -262,7 +262,7 @@ describe('notifications reducer', () => {
|
|||
emoji: '😢',
|
||||
chat_message: undefined,
|
||||
is_seen: false,
|
||||
}),
|
||||
})],
|
||||
]),
|
||||
unread: 1,
|
||||
hasMore: true,
|
||||
|
@ -274,8 +274,8 @@ describe('notifications reducer', () => {
|
|||
next: true,
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList([
|
||||
ImmutableMap({
|
||||
items: ImmutableOrderedMap([
|
||||
['10744', ImmutableMap({
|
||||
id: '10744',
|
||||
type: 'pleroma:emoji_reaction',
|
||||
account: '9vMAje101ngtjlMj7w',
|
||||
|
@ -284,8 +284,8 @@ describe('notifications reducer', () => {
|
|||
emoji: '😢',
|
||||
chat_message: undefined,
|
||||
is_seen: false,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10743', ImmutableMap({
|
||||
id: '10743',
|
||||
type: 'favourite',
|
||||
account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
|
@ -294,8 +294,8 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10741', ImmutableMap({
|
||||
id: '10741',
|
||||
type: 'favourite',
|
||||
account: '9v5cKMOPGqPcgfcWp6',
|
||||
|
@ -304,8 +304,8 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10734', ImmutableMap({
|
||||
id: '10734',
|
||||
type: 'pleroma:emoji_reaction',
|
||||
account: '9vMAje101ngtjlMj7w',
|
||||
|
@ -314,7 +314,7 @@ describe('notifications reducer', () => {
|
|||
emoji: '😢',
|
||||
chat_message: undefined,
|
||||
is_seen: false,
|
||||
}),
|
||||
})],
|
||||
]),
|
||||
unread: 1,
|
||||
hasMore: true,
|
||||
|
@ -324,7 +324,7 @@ describe('notifications reducer', () => {
|
|||
|
||||
it('should handle NOTIFICATIONS_EXPAND_SUCCESS with empty items and next set true', () => {
|
||||
const state = ImmutableMap({
|
||||
items: ImmutableList([]),
|
||||
items: ImmutableOrderedMap(),
|
||||
unread: 1,
|
||||
hasMore: true,
|
||||
isLoading: false,
|
||||
|
@ -335,8 +335,8 @@ describe('notifications reducer', () => {
|
|||
next: true,
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList([
|
||||
ImmutableMap({
|
||||
items: ImmutableOrderedMap([
|
||||
['10744', ImmutableMap({
|
||||
id: '10744',
|
||||
type: 'pleroma:emoji_reaction',
|
||||
account: '9vMAje101ngtjlMj7w',
|
||||
|
@ -345,8 +345,8 @@ describe('notifications reducer', () => {
|
|||
emoji: '😢',
|
||||
chat_message: undefined,
|
||||
is_seen: false,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10743', ImmutableMap({
|
||||
id: '10743',
|
||||
type: 'favourite',
|
||||
account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
|
@ -355,8 +355,8 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10741', ImmutableMap({
|
||||
id: '10741',
|
||||
type: 'favourite',
|
||||
account: '9v5cKMOPGqPcgfcWp6',
|
||||
|
@ -365,7 +365,7 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
})],
|
||||
]),
|
||||
unread: 1,
|
||||
hasMore: true,
|
||||
|
@ -375,8 +375,8 @@ describe('notifications reducer', () => {
|
|||
|
||||
it('should handle ACCOUNT_BLOCK_SUCCESS', () => {
|
||||
const state = ImmutableMap({
|
||||
items: ImmutableList([
|
||||
ImmutableMap({
|
||||
items: ImmutableOrderedMap([
|
||||
['10744', ImmutableMap({
|
||||
id: '10744',
|
||||
type: 'pleroma:emoji_reaction',
|
||||
account: '9vMAje101ngtjlMj7w',
|
||||
|
@ -385,8 +385,8 @@ describe('notifications reducer', () => {
|
|||
emoji: '😢',
|
||||
chat_message: undefined,
|
||||
is_seen: false,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10743', ImmutableMap({
|
||||
id: '10743',
|
||||
type: 'favourite',
|
||||
account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
|
@ -395,8 +395,8 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10741', ImmutableMap({
|
||||
id: '10741',
|
||||
type: 'favourite',
|
||||
account: '9v5cKMOPGqPcgfcWp6',
|
||||
|
@ -405,7 +405,7 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
})],
|
||||
]),
|
||||
});
|
||||
const action = {
|
||||
|
@ -413,8 +413,8 @@ describe('notifications reducer', () => {
|
|||
relationship: relationship,
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList([
|
||||
ImmutableMap({
|
||||
items: ImmutableOrderedMap([
|
||||
['10743', ImmutableMap({
|
||||
id: '10743',
|
||||
type: 'favourite',
|
||||
account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
|
@ -423,8 +423,8 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10741', ImmutableMap({
|
||||
id: '10741',
|
||||
type: 'favourite',
|
||||
account: '9v5cKMOPGqPcgfcWp6',
|
||||
|
@ -433,15 +433,15 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
})],
|
||||
]),
|
||||
}));
|
||||
});
|
||||
|
||||
it('should handle ACCOUNT_MUTE_SUCCESS', () => {
|
||||
const state = ImmutableMap({
|
||||
items: ImmutableList([
|
||||
ImmutableMap({
|
||||
items: ImmutableOrderedMap([
|
||||
['10744', ImmutableMap({
|
||||
id: '10744',
|
||||
type: 'pleroma:emoji_reaction',
|
||||
account: '9vMAje101ngtjlMj7w',
|
||||
|
@ -450,8 +450,8 @@ describe('notifications reducer', () => {
|
|||
emoji: '😢',
|
||||
chat_message: undefined,
|
||||
is_seen: false,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10743', ImmutableMap({
|
||||
id: '10743',
|
||||
type: 'favourite',
|
||||
account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
|
@ -460,8 +460,8 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10741', ImmutableMap({
|
||||
id: '10741',
|
||||
type: 'favourite',
|
||||
account: '9v5cKMOPGqPcgfcWp6',
|
||||
|
@ -470,7 +470,7 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
})],
|
||||
]),
|
||||
});
|
||||
const action = {
|
||||
|
@ -478,8 +478,8 @@ describe('notifications reducer', () => {
|
|||
relationship: relationship,
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList([
|
||||
ImmutableMap({
|
||||
items: ImmutableOrderedMap([
|
||||
['10743', ImmutableMap({
|
||||
id: '10743',
|
||||
type: 'favourite',
|
||||
account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
|
@ -488,8 +488,8 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10741', ImmutableMap({
|
||||
id: '10741',
|
||||
type: 'favourite',
|
||||
account: '9v5cKMOPGqPcgfcWp6',
|
||||
|
@ -498,43 +498,43 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
})],
|
||||
]),
|
||||
}));
|
||||
});
|
||||
|
||||
it('should handle NOTIFICATIONS_CLEAR', () => {
|
||||
const state = ImmutableMap({
|
||||
items: ImmutableList([]),
|
||||
items: ImmutableOrderedMap(),
|
||||
hasMore: true,
|
||||
});
|
||||
const action = {
|
||||
type: actions.NOTIFICATIONS_CLEAR,
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList([]),
|
||||
items: ImmutableOrderedMap(),
|
||||
hasMore: false,
|
||||
}));
|
||||
});
|
||||
|
||||
it('should handle NOTIFICATIONS_MARK_READ_REQUEST', () => {
|
||||
const state = ImmutableMap({
|
||||
items: ImmutableList([]),
|
||||
items: ImmutableOrderedMap(),
|
||||
});
|
||||
const action = {
|
||||
type: actions.NOTIFICATIONS_MARK_READ_REQUEST,
|
||||
lastRead: 35098814,
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList([]),
|
||||
items: ImmutableOrderedMap(),
|
||||
lastRead: 35098814,
|
||||
}));
|
||||
});
|
||||
|
||||
it('should handle TIMELINE_DELETE', () => {
|
||||
const state = ImmutableMap({
|
||||
items: ImmutableList([
|
||||
ImmutableMap({
|
||||
items: ImmutableOrderedMap([
|
||||
['10744', ImmutableMap({
|
||||
id: '10744',
|
||||
type: 'pleroma:emoji_reaction',
|
||||
account: '9vMAje101ngtjlMj7w',
|
||||
|
@ -543,8 +543,8 @@ describe('notifications reducer', () => {
|
|||
emoji: '😢',
|
||||
chat_message: undefined,
|
||||
is_seen: false,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10743', ImmutableMap({
|
||||
id: '10743',
|
||||
type: 'favourite',
|
||||
account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
|
@ -553,8 +553,8 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
ImmutableMap({
|
||||
})],
|
||||
['10741', ImmutableMap({
|
||||
id: '10741',
|
||||
type: 'favourite',
|
||||
account: '9v5cKMOPGqPcgfcWp6',
|
||||
|
@ -563,7 +563,7 @@ describe('notifications reducer', () => {
|
|||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
})],
|
||||
]),
|
||||
});
|
||||
const action = {
|
||||
|
@ -571,84 +571,87 @@ describe('notifications reducer', () => {
|
|||
id: '9vvNxoo5EFbbnfdXQu',
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList([]),
|
||||
items: ImmutableOrderedMap(),
|
||||
}));
|
||||
});
|
||||
|
||||
it('should handle TIMELINE_DISCONNECT', () => {
|
||||
const state = ImmutableMap({
|
||||
items: ImmutableList([
|
||||
ImmutableMap({
|
||||
id: '10744',
|
||||
type: 'pleroma:emoji_reaction',
|
||||
account: '9vMAje101ngtjlMj7w',
|
||||
created_at: '2020-06-10T02:54:39.000Z',
|
||||
status: '9vvNxoo5EFbbnfdXQu',
|
||||
emoji: '😢',
|
||||
chat_message: undefined,
|
||||
is_seen: false,
|
||||
}),
|
||||
ImmutableMap({
|
||||
id: '10743',
|
||||
type: 'favourite',
|
||||
account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
created_at: '2020-06-10T02:51:05.000Z',
|
||||
status: '9vvNxoo5EFbbnfdXQu',
|
||||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
ImmutableMap({
|
||||
id: '10741',
|
||||
type: 'favourite',
|
||||
account: '9v5cKMOPGqPcgfcWp6',
|
||||
created_at: '2020-06-10T02:05:06.000Z',
|
||||
status: '9vvNxoo5EFbbnfdXQu',
|
||||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
]),
|
||||
});
|
||||
const action = {
|
||||
type: TIMELINE_DISCONNECT,
|
||||
timeline: 'home',
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
items: ImmutableList([
|
||||
null,
|
||||
ImmutableMap({
|
||||
id: '10744',
|
||||
type: 'pleroma:emoji_reaction',
|
||||
account: '9vMAje101ngtjlMj7w',
|
||||
created_at: '2020-06-10T02:54:39.000Z',
|
||||
status: '9vvNxoo5EFbbnfdXQu',
|
||||
emoji: '😢',
|
||||
chat_message: undefined,
|
||||
is_seen: false,
|
||||
}),
|
||||
ImmutableMap({
|
||||
id: '10743',
|
||||
type: 'favourite',
|
||||
account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
created_at: '2020-06-10T02:51:05.000Z',
|
||||
status: '9vvNxoo5EFbbnfdXQu',
|
||||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
ImmutableMap({
|
||||
id: '10741',
|
||||
type: 'favourite',
|
||||
account: '9v5cKMOPGqPcgfcWp6',
|
||||
created_at: '2020-06-10T02:05:06.000Z',
|
||||
status: '9vvNxoo5EFbbnfdXQu',
|
||||
emoji: undefined,
|
||||
chat_message: undefined,
|
||||
is_seen: true,
|
||||
}),
|
||||
]),
|
||||
}));
|
||||
});
|
||||
// Disable for now
|
||||
// https://gitlab.com/soapbox-pub/soapbox-fe/-/issues/432
|
||||
//
|
||||
// it('should handle TIMELINE_DISCONNECT', () => {
|
||||
// const state = ImmutableMap({
|
||||
// items: ImmutableOrderedSet([
|
||||
// ImmutableMap({
|
||||
// id: '10744',
|
||||
// type: 'pleroma:emoji_reaction',
|
||||
// account: '9vMAje101ngtjlMj7w',
|
||||
// created_at: '2020-06-10T02:54:39.000Z',
|
||||
// status: '9vvNxoo5EFbbnfdXQu',
|
||||
// emoji: '😢',
|
||||
// chat_message: undefined,
|
||||
// is_seen: false,
|
||||
// }),
|
||||
// ImmutableMap({
|
||||
// id: '10743',
|
||||
// type: 'favourite',
|
||||
// account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
// created_at: '2020-06-10T02:51:05.000Z',
|
||||
// status: '9vvNxoo5EFbbnfdXQu',
|
||||
// emoji: undefined,
|
||||
// chat_message: undefined,
|
||||
// is_seen: true,
|
||||
// }),
|
||||
// ImmutableMap({
|
||||
// id: '10741',
|
||||
// type: 'favourite',
|
||||
// account: '9v5cKMOPGqPcgfcWp6',
|
||||
// created_at: '2020-06-10T02:05:06.000Z',
|
||||
// status: '9vvNxoo5EFbbnfdXQu',
|
||||
// emoji: undefined,
|
||||
// chat_message: undefined,
|
||||
// is_seen: true,
|
||||
// }),
|
||||
// ]),
|
||||
// });
|
||||
// const action = {
|
||||
// type: TIMELINE_DISCONNECT,
|
||||
// timeline: 'home',
|
||||
// };
|
||||
// expect(reducer(state, action)).toEqual(ImmutableMap({
|
||||
// items: ImmutableOrderedSet([
|
||||
// null,
|
||||
// ImmutableMap({
|
||||
// id: '10744',
|
||||
// type: 'pleroma:emoji_reaction',
|
||||
// account: '9vMAje101ngtjlMj7w',
|
||||
// created_at: '2020-06-10T02:54:39.000Z',
|
||||
// status: '9vvNxoo5EFbbnfdXQu',
|
||||
// emoji: '😢',
|
||||
// chat_message: undefined,
|
||||
// is_seen: false,
|
||||
// }),
|
||||
// ImmutableMap({
|
||||
// id: '10743',
|
||||
// type: 'favourite',
|
||||
// account: '9v5c6xSEgAi3Zu1Lv6',
|
||||
// created_at: '2020-06-10T02:51:05.000Z',
|
||||
// status: '9vvNxoo5EFbbnfdXQu',
|
||||
// emoji: undefined,
|
||||
// chat_message: undefined,
|
||||
// is_seen: true,
|
||||
// }),
|
||||
// ImmutableMap({
|
||||
// id: '10741',
|
||||
// type: 'favourite',
|
||||
// account: '9v5cKMOPGqPcgfcWp6',
|
||||
// created_at: '2020-06-10T02:05:06.000Z',
|
||||
// status: '9vvNxoo5EFbbnfdXQu',
|
||||
// emoji: undefined,
|
||||
// chat_message: undefined,
|
||||
// is_seen: true,
|
||||
// }),
|
||||
// ]),
|
||||
// }));
|
||||
// });
|
||||
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
CHAT_MESSAGES_FETCH_SUCCESS,
|
||||
CHAT_MESSAGE_SEND_REQUEST,
|
||||
CHAT_MESSAGE_SEND_SUCCESS,
|
||||
CHAT_MESSAGE_DELETE_SUCCESS,
|
||||
} from 'soapbox/actions/chats';
|
||||
import { STREAMING_CHAT_UPDATE } from 'soapbox/actions/streaming';
|
||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||
|
@ -59,6 +60,8 @@ export default function chatMessageLists(state = initialState, action) {
|
|||
return updateList(state, action.chatId, action.chatMessages.map(chat => chat.id));
|
||||
case CHAT_MESSAGE_SEND_SUCCESS:
|
||||
return replaceMessage(state, action.chatId, action.uuid, action.chatMessage.id);
|
||||
case CHAT_MESSAGE_DELETE_SUCCESS:
|
||||
return state.update(action.chatId, chat => chat.delete(action.messageId));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ import {
|
|||
CHAT_MESSAGES_FETCH_SUCCESS,
|
||||
CHAT_MESSAGE_SEND_REQUEST,
|
||||
CHAT_MESSAGE_SEND_SUCCESS,
|
||||
CHAT_MESSAGE_DELETE_REQUEST,
|
||||
CHAT_MESSAGE_DELETE_SUCCESS,
|
||||
} from 'soapbox/actions/chats';
|
||||
import { STREAMING_CHAT_UPDATE } from 'soapbox/actions/streaming';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
|
@ -43,6 +45,11 @@ export default function chatMessages(state = initialState, action) {
|
|||
return importMessage(state, fromJS(action.chatMessage)).delete(action.uuid);
|
||||
case STREAMING_CHAT_UPDATE:
|
||||
return importLastMessages(state, fromJS([action.chat]));
|
||||
case CHAT_MESSAGE_DELETE_REQUEST:
|
||||
return state.update(action.messageId, chatMessage =>
|
||||
chatMessage.set('pending', true).set('deleting', true));
|
||||
case CHAT_MESSAGE_DELETE_SUCCESS:
|
||||
return state.delete(action.messageId);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,7 @@ import {
|
|||
} from '../actions/accounts';
|
||||
import { CONTEXT_FETCH_SUCCESS } from '../actions/statuses';
|
||||
import { TIMELINE_DELETE, TIMELINE_UPDATE } from '../actions/timelines';
|
||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import compareId from '../compare_id';
|
||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
inReplyTos: ImmutableMap(),
|
||||
|
@ -16,26 +15,16 @@ const normalizeContext = (immutableState, id, ancestors, descendants) => immutab
|
|||
state.update('inReplyTos', immutableAncestors => immutableAncestors.withMutations(inReplyTos => {
|
||||
state.update('replies', immutableDescendants => immutableDescendants.withMutations(replies => {
|
||||
function addReply({ id, in_reply_to_id }) {
|
||||
if (in_reply_to_id && !inReplyTos.has(id)) {
|
||||
|
||||
replies.update(in_reply_to_id, ImmutableList(), siblings => {
|
||||
const index = siblings.findLastIndex(sibling => compareId(sibling, id) < 0);
|
||||
return siblings.insert(index + 1, id);
|
||||
if (in_reply_to_id) {
|
||||
replies.update(in_reply_to_id, ImmutableOrderedSet(), siblings => {
|
||||
return siblings.add(id).sort();
|
||||
});
|
||||
|
||||
inReplyTos.set(id, in_reply_to_id);
|
||||
}
|
||||
}
|
||||
|
||||
// We know in_reply_to_id of statuses but `id` itself.
|
||||
// So we assume that the status of the id replies to last ancestors.
|
||||
|
||||
ancestors.forEach(addReply);
|
||||
|
||||
if (ancestors[0]) {
|
||||
addReply({ id, in_reply_to_id: ancestors[ancestors.length - 1].id });
|
||||
}
|
||||
|
||||
descendants.forEach(addReply);
|
||||
}));
|
||||
}));
|
||||
|
@ -76,12 +65,12 @@ const filterContexts = (state, relationship, statuses) => {
|
|||
const updateContext = (state, status) => {
|
||||
if (status.in_reply_to_id) {
|
||||
return state.withMutations(mutable => {
|
||||
const replies = mutable.getIn(['replies', status.in_reply_to_id], ImmutableList());
|
||||
const replies = mutable.getIn(['replies', status.in_reply_to_id], ImmutableOrderedSet());
|
||||
|
||||
mutable.setIn(['inReplyTos', status.id], status.in_reply_to_id);
|
||||
|
||||
if (!replies.includes(status.id)) {
|
||||
mutable.setIn(['replies', status.in_reply_to_id], replies.push(status.id));
|
||||
mutable.setIn(['replies', status.in_reply_to_id], replies.add(status.id).sort());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,22 +15,28 @@ import {
|
|||
ACCOUNT_BLOCK_SUCCESS,
|
||||
ACCOUNT_MUTE_SUCCESS,
|
||||
} from '../actions/accounts';
|
||||
import { TIMELINE_DELETE, TIMELINE_DISCONNECT } from '../actions/timelines';
|
||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import compareId from '../compare_id';
|
||||
import { TIMELINE_DELETE } from '../actions/timelines';
|
||||
import { Map as ImmutableMap, OrderedMap as ImmutableOrderedMap } from 'immutable';
|
||||
import { get } from 'lodash';
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
items: ImmutableList(),
|
||||
items: ImmutableOrderedMap(),
|
||||
hasMore: true,
|
||||
top: false,
|
||||
unread: 0,
|
||||
isLoading: false,
|
||||
queuedNotifications: ImmutableList(), //max = MAX_QUEUED_NOTIFICATIONS
|
||||
queuedNotifications: ImmutableOrderedMap(), //max = MAX_QUEUED_NOTIFICATIONS
|
||||
totalQueuedNotificationsCount: 0, //used for queuedItems overflow for MAX_QUEUED_NOTIFICATIONS+
|
||||
lastRead: -1,
|
||||
});
|
||||
|
||||
// For sorting the notifications
|
||||
const comparator = (a, b) => {
|
||||
if (a.get('id') < b.get('id')) return 1;
|
||||
if (a.get('id') > b.get('id')) return -1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
const notificationToMap = notification => ImmutableMap({
|
||||
id: notification.id,
|
||||
type: notification.type,
|
||||
|
@ -42,85 +48,67 @@ const notificationToMap = notification => ImmutableMap({
|
|||
is_seen: get(notification, ['pleroma', 'is_seen'], true),
|
||||
});
|
||||
|
||||
// https://gitlab.com/soapbox-pub/soapbox-fe/-/issues/424
|
||||
const isValid = notification => Boolean(notification.account.id);
|
||||
|
||||
const normalizeNotification = (state, notification) => {
|
||||
const top = state.get('top');
|
||||
|
||||
if (!top) {
|
||||
state = state.update('unread', unread => unread + 1);
|
||||
if (!top) state = state.update('unread', unread => unread + 1);
|
||||
|
||||
return state.update('items', map => {
|
||||
if (top && map.size > 40) {
|
||||
map = map.take(20);
|
||||
}
|
||||
|
||||
return state.update('items', list => {
|
||||
if (top && list.size > 40) {
|
||||
list = list.take(20);
|
||||
}
|
||||
|
||||
return list.unshift(notificationToMap(notification));
|
||||
return map.set(notification.id, notificationToMap(notification)).sort(comparator);
|
||||
});
|
||||
};
|
||||
|
||||
const expandNormalizedNotifications = (state, notifications, next) => {
|
||||
let items = ImmutableList();
|
||||
const processRawNotifications = notifications => (
|
||||
ImmutableOrderedMap(
|
||||
notifications
|
||||
.filter(isValid)
|
||||
.map(n => [n.id, notificationToMap(n)])
|
||||
));
|
||||
|
||||
notifications.forEach((n, i) => {
|
||||
items = items.set(i, notificationToMap(n));
|
||||
});
|
||||
const expandNormalizedNotifications = (state, notifications, next) => {
|
||||
const items = processRawNotifications(notifications);
|
||||
|
||||
return state.withMutations(mutable => {
|
||||
if (!items.isEmpty()) {
|
||||
mutable.update('items', list => {
|
||||
const lastIndex = 1 + list.findLastIndex(
|
||||
item => item !== null && (compareId(item.get('id'), items.last().get('id')) > 0 || item.get('id') === items.last().get('id'))
|
||||
);
|
||||
|
||||
const firstIndex = 1 + list.take(lastIndex).findLastIndex(
|
||||
item => item !== null && compareId(item.get('id'), items.first().get('id')) > 0
|
||||
);
|
||||
|
||||
return list.take(firstIndex).concat(items, list.skip(lastIndex));
|
||||
});
|
||||
}
|
||||
|
||||
if (!next) {
|
||||
mutable.set('hasMore', false);
|
||||
}
|
||||
mutable.update('items', map => map.merge(items).sort(comparator));
|
||||
|
||||
if (!next) mutable.set('hasMore', false);
|
||||
mutable.set('isLoading', false);
|
||||
});
|
||||
};
|
||||
|
||||
const filterNotifications = (state, relationship) => {
|
||||
return state.update('items', list => list.filterNot(item => item !== null && item.get('account') === relationship.id));
|
||||
return state.update('items', map => map.filterNot(item => item !== null && item.get('account') === relationship.id));
|
||||
};
|
||||
|
||||
const updateTop = (state, top) => {
|
||||
if (top) {
|
||||
state = state.set('unread', 0);
|
||||
}
|
||||
|
||||
if (top) state = state.set('unread', 0);
|
||||
return state.set('top', top);
|
||||
};
|
||||
|
||||
const deleteByStatus = (state, statusId) => {
|
||||
return state.update('items', list => list.filterNot(item => item !== null && item.get('status') === statusId));
|
||||
return state.update('items', map => map.filterNot(item => item !== null && item.get('status') === statusId));
|
||||
};
|
||||
|
||||
const updateNotificationsQueue = (state, notification, intlMessages, intlLocale) => {
|
||||
const queuedNotifications = state.getIn(['queuedNotifications'], ImmutableList());
|
||||
const listedNotifications = state.getIn(['items'], ImmutableList());
|
||||
const queuedNotifications = state.getIn(['queuedNotifications'], ImmutableOrderedMap());
|
||||
const listedNotifications = state.getIn(['items'], ImmutableOrderedMap());
|
||||
const totalQueuedNotificationsCount = state.getIn(['totalQueuedNotificationsCount'], 0);
|
||||
|
||||
let alreadyExists = queuedNotifications.find(existingQueuedNotification => existingQueuedNotification.id === notification.id);
|
||||
if (!alreadyExists) alreadyExists = listedNotifications.find(existingListedNotification => existingListedNotification.get('id') === notification.id);
|
||||
|
||||
if (alreadyExists) {
|
||||
return state;
|
||||
}
|
||||
const alreadyExists = queuedNotifications.has(notification.id) || listedNotifications.has(notification.id);
|
||||
if (alreadyExists) return state;
|
||||
|
||||
let newQueuedNotifications = queuedNotifications;
|
||||
|
||||
return state.withMutations(mutable => {
|
||||
if (totalQueuedNotificationsCount <= MAX_QUEUED_NOTIFICATIONS) {
|
||||
mutable.set('queuedNotifications', newQueuedNotifications.push({
|
||||
mutable.set('queuedNotifications', newQueuedNotifications.set(notification.id, {
|
||||
notification,
|
||||
intlMessages,
|
||||
intlLocale,
|
||||
|
@ -130,6 +118,9 @@ const updateNotificationsQueue = (state, notification, intlMessages, intlLocale)
|
|||
});
|
||||
};
|
||||
|
||||
const countUnseen = notifications => notifications.reduce((acc, cur) =>
|
||||
get(cur, ['pleroma', 'is_seen'], false) === false ? acc + 1 : acc, 0);
|
||||
|
||||
export default function notifications(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case NOTIFICATIONS_EXPAND_REQUEST:
|
||||
|
@ -137,7 +128,7 @@ export default function notifications(state = initialState, action) {
|
|||
case NOTIFICATIONS_EXPAND_FAIL:
|
||||
return state.set('isLoading', false);
|
||||
case NOTIFICATIONS_FILTER_SET:
|
||||
return state.set('items', ImmutableList()).set('hasMore', true);
|
||||
return state.set('items', ImmutableOrderedMap()).set('hasMore', true);
|
||||
case NOTIFICATIONS_SCROLL_TOP:
|
||||
return updateTop(state, action.top);
|
||||
case NOTIFICATIONS_UPDATE:
|
||||
|
@ -146,12 +137,11 @@ export default function notifications(state = initialState, action) {
|
|||
return updateNotificationsQueue(state, action.notification, action.intlMessages, action.intlLocale);
|
||||
case NOTIFICATIONS_DEQUEUE:
|
||||
return state.withMutations(mutable => {
|
||||
mutable.set('queuedNotifications', ImmutableList());
|
||||
mutable.set('queuedNotifications', ImmutableOrderedMap());
|
||||
mutable.set('totalQueuedNotificationsCount', 0);
|
||||
});
|
||||
case NOTIFICATIONS_EXPAND_SUCCESS:
|
||||
const legacyUnread = action.notifications.reduce((acc, cur) =>
|
||||
get(cur, ['pleroma', 'is_seen'], false) === false ? acc + 1 : acc, 0);
|
||||
const legacyUnread = countUnseen(action.notifications);
|
||||
return expandNormalizedNotifications(state, action.notifications, action.next)
|
||||
.merge({ unread: Math.max(legacyUnread, state.get('unread')) });
|
||||
case ACCOUNT_BLOCK_SUCCESS:
|
||||
|
@ -159,15 +149,21 @@ export default function notifications(state = initialState, action) {
|
|||
case ACCOUNT_MUTE_SUCCESS:
|
||||
return action.relationship.muting_notifications ? filterNotifications(state, action.relationship) : state;
|
||||
case NOTIFICATIONS_CLEAR:
|
||||
return state.set('items', ImmutableList()).set('hasMore', false);
|
||||
return state.set('items', ImmutableOrderedMap()).set('hasMore', false);
|
||||
case NOTIFICATIONS_MARK_READ_REQUEST:
|
||||
return state.set('lastRead', action.lastRead);
|
||||
case TIMELINE_DELETE:
|
||||
return deleteByStatus(state, action.id);
|
||||
case TIMELINE_DISCONNECT:
|
||||
return action.timeline === 'home' ?
|
||||
state.update('items', items => items.first() ? items.unshift(null) : items) :
|
||||
state;
|
||||
|
||||
// Disable for now
|
||||
// https://gitlab.com/soapbox-pub/soapbox-fe/-/issues/432
|
||||
//
|
||||
// case TIMELINE_DISCONNECT:
|
||||
// // This is kind of a hack - `null` renders a LoadGap in the component
|
||||
// // https://github.com/tootsuite/mastodon/pull/6886
|
||||
// return action.timeline === 'home' ?
|
||||
// state.update('items', items => items.first() ? ImmutableOrderedSet([null]).union(items) : items) :
|
||||
// state;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -76,3 +76,6 @@
|
|||
@import 'components/profile_hover_card';
|
||||
@import 'components/filters';
|
||||
@import 'components/mfa_form';
|
||||
|
||||
// Holiday
|
||||
@import 'holiday/halloween';
|
||||
|
|
|
@ -94,6 +94,41 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.audio-toggle .react-toggle-thumb {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
border: 1px solid var(--brand-color--med);
|
||||
}
|
||||
|
||||
.audio-toggle .react-toggle {
|
||||
height: 16px;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
.audio-toggle .react-toggle-track {
|
||||
height: 16px;
|
||||
width: 34px;
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
|
||||
.audio-toggle .react-toggle-track-check {
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
}
|
||||
|
||||
.react-toggle--checked .react-toggle-thumb {
|
||||
left: 19px;
|
||||
}
|
||||
|
||||
.audio-toggle .react-toggle-track-x {
|
||||
right: 4px;
|
||||
bottom: 4px;
|
||||
}
|
||||
|
||||
.fa {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
|
@ -111,14 +146,23 @@
|
|||
max-width: 70%;
|
||||
border-radius: 10px;
|
||||
background-color: var(--background-color);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
overflow-wrap: break-word;
|
||||
white-space: break-spaces;
|
||||
position: relative;
|
||||
|
||||
a {
|
||||
color: var(--brand-color--hicontrast);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active, {
|
||||
.chat-message__menu {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--me .chat-message__bubble {
|
||||
|
@ -129,6 +173,17 @@
|
|||
&--pending .chat-message__bubble {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&__menu {
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
background: var(--background-color);
|
||||
border-radius: 999px;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-list {
|
||||
|
@ -152,6 +207,10 @@
|
|||
.display-name {
|
||||
display: flex;
|
||||
|
||||
.hover-ref-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
bdi {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
@ -274,7 +333,38 @@
|
|||
border-radius: 0 0 10px 10px;
|
||||
|
||||
&__actions textarea {
|
||||
padding: 10px;
|
||||
padding: 10px 40px 10px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width: 630px) {
|
||||
.columns-area__panels__main .columns-area {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.columns-area__panels__main {
|
||||
padding: 0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.columns-area--mobile .column {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.page {
|
||||
.chat-box {
|
||||
border-radius: 0;
|
||||
border: 2px solid var(--foreground-color);
|
||||
|
||||
&__actions {
|
||||
padding: 0;
|
||||
|
||||
textarea {
|
||||
height: 4em;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -297,6 +387,7 @@
|
|||
margin-left: auto;
|
||||
padding-right: 15px;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
|
||||
.account__avatar {
|
||||
margin-right: 7px;
|
||||
|
@ -368,3 +459,11 @@
|
|||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-messages__divider {
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
||||
padding: 14px 0 2px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
|
|
@ -703,3 +703,16 @@
|
|||
.column-link--transparent .icon-with-badge__badge {
|
||||
border-color: var(--background-color);
|
||||
}
|
||||
|
||||
.column__switch .audio-toggle {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
top: 12px;
|
||||
right: 14px;
|
||||
|
||||
.react-toggle-track-check,
|
||||
.react-toggle-track-x {
|
||||
height: 16px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,16 +105,3 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.detailed-status {
|
||||
.profile-hover-card {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide the popper when the reference is hidden */
|
||||
#popper[data-popper-reference-hidden] {
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
position: fixed;
|
||||
flex-direction: column;
|
||||
width: 275px;
|
||||
height: 100vh;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
@ -30,12 +29,10 @@
|
|||
}
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
flex: 1 1;
|
||||
flex-direction: column;
|
||||
padding-bottom: 40px;
|
||||
overflow-y: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__section {
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
body.halloween {
|
||||
// Set brand color to orange
|
||||
--brand-color_h: 29.727272727272727;
|
||||
--brand-color_s: 100%;
|
||||
--brand-color_l: 43.13725490196079%;
|
||||
|
||||
// Stars BG
|
||||
background-color: #904700; // Color matches twinkle.svg
|
||||
background-image: url('../images/halloween/starfield.png');
|
||||
background-size: cover;
|
||||
background-attachment: fixed;
|
||||
background-position: center;
|
||||
|
||||
// Full-screen pseudo-elements to hold BG graphics
|
||||
&::before,
|
||||
&::after,
|
||||
.app-holder::before,
|
||||
.app-holder::after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -100;
|
||||
}
|
||||
|
||||
// Spiderweb BG
|
||||
&::before {
|
||||
background-image: url('../images/halloween/spiderweb.svg');
|
||||
}
|
||||
|
||||
// Twinkle effect by masking with semi-transparent animated circles
|
||||
&::after {
|
||||
z-index: -101;
|
||||
background: transparent url("../images/halloween/twinkle.svg") repeat top center;
|
||||
animation: halloween-twinkle 200s linear infinite;
|
||||
}
|
||||
|
||||
.app-holder {
|
||||
// Black vignette
|
||||
&::before {
|
||||
background-image: radial-gradient(
|
||||
circle,
|
||||
transparent 0%,
|
||||
transparent 60%,
|
||||
#000 100%
|
||||
);
|
||||
}
|
||||
|
||||
// Floating clouds BG
|
||||
&::after {
|
||||
background: transparent url("../images/halloween/clouds.png") repeat top center;
|
||||
animation: halloween-clouds 200s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
// Dangling spider
|
||||
.ui .page__top::after,
|
||||
.ui .page__columns::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
right: 20px;
|
||||
background-image: url('../images/halloween/spider.svg');
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: top right;
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ui .page__columns::after {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
}
|
||||
|
||||
.ui .page__top::after {
|
||||
position: absolute;
|
||||
bottom: -100px;
|
||||
}
|
||||
|
||||
.ui .page__top + .page__columns::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Witch emblem
|
||||
.getting-started__footer::before {
|
||||
content: '';
|
||||
display: block;
|
||||
background-image: url('../images/halloween/halloween-emblem.svg');
|
||||
background-size: contain;
|
||||
background-position: left;
|
||||
background-repeat: no-repeat;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
// Color fixes
|
||||
// Elements directly over the BG need static colors that don't change
|
||||
// regardless of the theme-mode
|
||||
.getting-started__footer {
|
||||
color: #fff;
|
||||
|
||||
a {
|
||||
color: hsla(0, 0%, 100%, 0.4);
|
||||
}
|
||||
|
||||
p {
|
||||
color: hsla(0, 0%, 100%, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
.profile-info-panel {
|
||||
color: #fff;
|
||||
|
||||
&-content__name h1 {
|
||||
span:first-of-type {
|
||||
color: hsla(0, 0%, 100%, 0.6);
|
||||
}
|
||||
|
||||
small {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&-content__bio {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&-content__bio a,
|
||||
&-content__fields a {
|
||||
color: hsl(
|
||||
var(--brand-color_h),
|
||||
var(--brand-color_s),
|
||||
calc(var(--brand-color_l) + 8%)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Animations
|
||||
@keyframes halloween-twinkle {
|
||||
from { background-position: 0 0; }
|
||||
to { background-position: -10000px 5000px; }
|
||||
}
|
||||
|
||||
@keyframes halloween-clouds {
|
||||
from { background-position: 0 0; }
|
||||
to { background-position: 10000px 0; }
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
# Installing Soapbox FE via YunoHost
|
||||
|
||||
If you want to install Soapbox FE to a Pleroma instance installed using [YunoHost](https://yunohost.org), you can do so by following these steps.
|
||||
|
||||
## 1. Download the build
|
||||
|
||||
First, download the latest build of Soapbox FE from GitLab.
|
||||
|
||||
```sh
|
||||
curl -L https://gitlab.com/soapbox-pub/soapbox-fe/-/jobs/artifacts/v1.0.0/download?job=build-production -o soapbox-fe.zip
|
||||
```
|
||||
|
||||
## 2. Unzip the build
|
||||
|
||||
Then, unzip the build to the Pleroma directory under YunoHost's directory:
|
||||
|
||||
```sh
|
||||
busybox unzip soapbox-fe.zip -o -d /home/yunohost.app/pleroma/
|
||||
```
|
||||
|
||||
**That's it! 🎉 Soapbox FE is installed.** The change will take effect immediately, just refresh your browser tab. It's not necessary to restart the Pleroma service.
|
||||
|
||||
---
|
||||
|
||||
Thank you to [@jeroen@social.franssen.xyz](https://social.franssen.xyz/@jeroen) for discovering this method.
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
}
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue