Compare commits

...

170 commits

Author SHA1 Message Date
Erin Shepherd c38f62700a Merge remote-tracking branch 'upstream/main' 2022-11-12 10:31:04 +00:00
Claire c813df2ebb
Merge pull request #1917 from ClearlyClaire/glitch-soc/fixes/not-recommended-label
Fix “not recommended” label being shown as “recommended”
2022-11-12 11:10:39 +01:00
Claire 0d43d9926a Make trendable_by_default not apply to posts 2022-11-12 10:59:17 +01:00
Claire 1ce29aeabf Change "Allow trends without prior review' setting to include statuses
Port SCSS changes from 546672e292 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-12 10:59:17 +01:00
Claire fdfacb0ec0 Revert "Revert "Change "Allow trends without prior review" setting to include statuses (#17977)""
This reverts commit bfc539cfb4.
2022-11-12 10:17:22 +01:00
Claire 73b68fcabb
Fix styling of advanced options dropdown (#1916)
Fixes #1914
2022-11-12 09:59:28 +01:00
atsuchan 6df9d388e7
Update Flavour 'ja' Translation (#1911) 2022-11-10 17:26:28 +01:00
Claire ee7e49d1b1
Merge pull request #1910 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes
2022-11-10 13:27:40 +01:00
Eugen Rochko c4d2c72924 [Glitch] Add option to open original page in dropdowns of remote content in web UI
Port ef582dc4f2 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-10 11:06:56 +01:00
Sasha Sorokin 099b3011aa [Glitch] Remove aria-pressed where it's redundant
Port d055d75172 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-10 10:25:43 +01:00
Eugen Rochko 65b6c4f6df [Glitch] Change larger reblogs/favourites numbers to be shortened in web UI
Port 7bdb2433f1 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-10 10:15:21 +01:00
Effy Elden c722c4cce8 [Glitch] Remove unused timeline_container to fix linter errors
Port 8fdbb4d00d to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-10 09:54:19 +01:00
Eugen Rochko 41ea39903d [Glitch] Fix confusing wording in interaction modal in web UI
Port 16122761c5 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-10 09:53:06 +01:00
Eugen Rochko d3a29a136c [Glitch] Fix profile header being cut off in light theme in web UI
Port e37e8deb0f to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-10 09:51:46 +01:00
Claire c118918520 Merge branch 'main' into glitch-soc/merge-upstream
Conflicts:
- `app/models/custom_emoji.rb`:
  Not a real conflict, just upstream changing a line too close to
  a glitch-soc-specific validation.
  Applied upstream changes.
- `app/models/public_feed.rb`:
  Not a real conflict, just upstream changing a line too close to
  a glitch-soc-specific parameter documentation.
  Applied upstream changes.
2022-11-10 09:36:47 +01:00
Effy Elden 8fdbb4d00d
Remove unused timeline_container to fix linter errors (#20305) 2022-11-10 08:50:45 +01:00
Eugen Rochko 7bdb2433f1
Change larger reblogs/favourites numbers to be shortened in web UI (#20303) 2022-11-10 08:49:59 +01:00
Eugen Rochko 16122761c5
Fix confusing wording in interaction modal in web UI (#20302) 2022-11-10 08:49:48 +01:00
Eugen Rochko ef582dc4f2
Add option to open original page in dropdowns of remote content in web UI (#20299)
Change profile picture click to open profile picture in modal in web UI
2022-11-10 08:49:35 +01:00
Eugen Rochko e37e8deb0f
Fix profile header being cut off in light theme in web UI (#20298) 2022-11-10 07:32:37 +01:00
Eugen Rochko 9965a23b04
Change link verification to ignore IDN domains (#20295)
Fix #3833
2022-11-10 06:27:45 +01:00
James Tucker 78a6b871fe
Improve performance by avoiding regex construction (#20215)
```ruby
10.times { p /#{FOO}/.object_id }
10.times { p FOO_RE.object_id }
```
2022-11-10 05:49:30 +01:00
Eugen Rochko 0cd0786aef
Revert filtering public timelines by locale by default (#20294) 2022-11-10 05:34:42 +01:00
trwnh b280a255c4
Change master branch to main branch (#20290) 2022-11-10 04:02:05 +01:00
Eugen Rochko 45ce858fd9
Fix mailers queue not being used for mailers (#20274)
Regression since Rails 6.1
2022-11-10 02:31:09 +01:00
Claire a5394980f2
Fix NameError in Webfinger redirect handling in ActivityPub::FetchRemoteActorService (#20260) 2022-11-09 20:10:38 +01:00
Eugen Rochko cd0a87f170
New Crowdin updates (#20016)
* New translations en.json (Telugu)

* New translations en.yml (Telugu)

* New translations en.yml (Occitan)

* New translations en.json (Serbian (Latin))

* New translations en.yml (Kabyle)

* New translations en.json (Igbo)

* New translations en.yml (Burmese)

* New translations en.json (Burmese)

* New translations activerecord.en.yml (Frisian)

* New translations en.yml (Standard Moroccan Tamazight)

* New translations en.json (Standard Moroccan Tamazight)

* New translations en.yml (Silesian)

* New translations en.json (Silesian)

* New translations en.yml (Taigi)

* New translations en.json (Taigi)

* New translations en.json (Kabyle)

* New translations en.yml (Serbian (Latin))

* New translations en.yml (Sanskrit)

* New translations en.json (Sanskrit)

* New translations en.yml (Sardinian)

* New translations en.json (Sardinian)

* New translations en.yml (Corsican)

* New translations en.json (Corsican)

* New translations en.yml (Sorani (Kurdish))

* New translations en.json (Sorani (Kurdish))

* New translations en.yml (Kurmanji (Kurdish))

* New translations en.json (Kurmanji (Kurdish))

* New translations en.yml (Igbo)

* New translations en.json (Hebrew)

* New translations en.json (Polish)

* New translations doorkeeper.en.yml (Frisian)

* New translations en.json (Latvian)

* New translations en.json (Icelandic)

* New translations en.yml (Swedish)

* New translations en.json (Swedish)

* New translations en.json (Slovenian)

* New translations en.json (Russian)

* New translations en.json (Italian)

* New translations en.json (German)

* New translations en.yml (Hebrew)

* New translations en.yml (Finnish)

* New translations en.json (Finnish)

* New translations en.yml (Danish)

* New translations en.json (Afrikaans)

* New translations en.json (Spanish)

* New translations en.json (French)

* New translations en.json (Dutch)

* New translations simple_form.en.yml (Hebrew)

* New translations en.json (Hebrew)

* New translations en.json (Spanish, Argentina)

* New translations activerecord.en.yml (Hebrew)

* New translations simple_form.en.yml (Occitan)

* New translations doorkeeper.en.yml (Hebrew)

* New translations simple_form.en.yml (Hebrew)

* New translations en.yml (Occitan)

* New translations en.json (Welsh)

* New translations en.yml (Chinese Traditional)

* New translations en.json (German)

* New translations en.json (Chinese Traditional)

* New translations en.json (Ukrainian)

* New translations en.json (Portuguese)

* New translations en.yml (Hebrew)

* New translations en.json (Finnish)

* New translations en.json (Japanese)

* New translations devise.en.yml (Chinese Traditional)

* New translations en.yml (Thai)

* New translations en.json (Hebrew)

* New translations en.json (Thai)

* New translations en.json (Greek)

* New translations en.yml (Hebrew)

* New translations en.json (Norwegian Nynorsk)

* New translations en.json (Occitan)

* New translations simple_form.en.yml (Hebrew)

* New translations simple_form.en.yml (Thai)

* New translations simple_form.en.yml (Norwegian Nynorsk)

* New translations en.json (Thai)

* New translations en.json (Catalan)

* New translations en.yml (Dutch)

* New translations simple_form.en.yml (Dutch)

* New translations en.json (Polish)

* New translations simple_form.en.yml (Thai)

* New translations en.json (Esperanto)

* New translations en.json (Chinese Simplified)

* New translations en.json (Irish)

* New translations activerecord.en.yml (Irish)

* New translations en.json (Irish)

* New translations en.yml (Dutch)

* New translations en.yml (Portuguese, Brazilian)

* New translations simple_form.en.yml (Italian)

* New translations en.json (Danish)

* New translations en.json (Galician)

* New translations simple_form.en.yml (Galician)

* New translations simple_form.en.yml (Norwegian Nynorsk)

* New translations en.json (Czech)

* New translations en.json (Turkish)

* New translations en.json (Vietnamese)

* New translations simple_form.en.yml (Norwegian Nynorsk)

* New translations en.json (Bulgarian)

* New translations en.json (Czech)

* New translations en.json (Albanian)

* New translations en.json (Arabic)

* New translations en.json (Chinese Traditional, Hong Kong)

* New translations en.json (Bulgarian)

* New translations en.json (Macedonian)

* New translations en.json (Chinese Traditional, Hong Kong)

* New translations en.json (Kurmanji (Kurdish))

* New translations en.json (Bulgarian)

* New translations devise.en.yml (Polish)

* New translations en.json (Bulgarian)

* New translations en.json (Hungarian)

* New translations en.yml (Japanese)

* New translations en.json (Norwegian)

* New translations en.json (Bulgarian)

* New translations en.json (Korean)

* New translations en.json (Scottish Gaelic)

* New translations en.yml (Scottish Gaelic)

* New translations simple_form.en.yml (Scottish Gaelic)

* New translations activerecord.en.yml (Scottish Gaelic)

* New translations devise.en.yml (Scottish Gaelic)

* New translations doorkeeper.en.yml (Scottish Gaelic)

* New translations en.json (Bulgarian)

* New translations en.json (German)

* New translations en.json (Catalan)

* New translations en.yml (Catalan)

* New translations en.json (Latvian)

* New translations en.yml (Latvian)

* New translations simple_form.en.yml (Catalan)

* New translations simple_form.en.yml (Latvian)

* New translations en.json (Esperanto)

* New translations en.json (Catalan)

* New translations en.yml (Catalan)

* New translations en.json (Norwegian)

* New translations en.json (Vietnamese)

* New translations en.yml (Esperanto)

* New translations doorkeeper.en.yml (Frisian)

* New translations en.yml (Romanian)

* New translations en.yml (Frisian)

* New translations en.json (Norwegian)

* New translations en.yml (Russian)

* New translations en.yml (Esperanto)

* New translations doorkeeper.en.yml (Frisian)

* New translations en.json (Norwegian)

* New translations en.yml (Russian)

* New translations en.yml (Portuguese, Brazilian)

* New translations en.json (Norwegian)

* New translations en.json (Swedish)

* New translations en.json (Occitan)

* New translations en.json (Afrikaans)

* New translations en.json (Catalan)

* New translations en.json (Norwegian)

* New translations en.json (Swedish)

* New translations en.yml (Norwegian Nynorsk)

* New translations en.json (Welsh)

* New translations en.yml (Esperanto)

* New translations en.json (Occitan)

* New translations doorkeeper.en.yml (French)

* New translations activerecord.en.yml (Norwegian)

* New translations activerecord.en.yml (Welsh)

* New translations devise.en.yml (Norwegian)

* New translations devise.en.yml (Esperanto)

* New translations en.json (Chinese Simplified)

* New translations en.json (Welsh)

* New translations doorkeeper.en.yml (Norwegian)

* New translations activerecord.en.yml (Norwegian)

* New translations devise.en.yml (Norwegian)

* New translations en.json (Dutch)

* New translations en.json (Irish)

* New translations en.yml (Norwegian)

* New translations doorkeeper.en.yml (Norwegian)

* New translations en.json (Dutch)

* New translations en.json (Irish)

* New translations en.yml (Dutch)

* New translations simple_form.en.yml (Dutch)

* New translations en.json (Norwegian)

* New translations simple_form.en.yml (Dutch)

* New translations en.json (Irish)

* New translations en.yml (Dutch)

* New translations simple_form.en.yml (Dutch)

* New translations en.json (English, United Kingdom)

* New translations simple_form.en.yml (English, United Kingdom)

* New translations doorkeeper.en.yml (English, United Kingdom)

* New translations activerecord.en.yml (English, United Kingdom)

* New translations en.json (Dutch)

* New translations en.json (Irish)

* New translations en.yml (Irish)

* New translations en.json (Portuguese, Brazilian)

* New translations en.yml (Portuguese, Brazilian)

* New translations simple_form.en.yml (Irish)

* New translations en.json (Irish)

* New translations en.yml (Irish)

* New translations en.yml (Portuguese, Brazilian)

* New translations simple_form.en.yml (Irish)

* New translations doorkeeper.en.yml (Irish)

* New translations en.json (Bulgarian)

* New translations en.json (Irish)

* New translations en.yml (Irish)

* New translations simple_form.en.yml (Irish)

* New translations doorkeeper.en.yml (Irish)

* New translations en.json (Bulgarian)

* New translations en.yml (Irish)

* New translations en.json (Chinese Traditional)

* New translations en.json (Galician)

* New translations en.json (Bulgarian)

* New translations en.json (Latvian)

* New translations en.yml (Latvian)

* New translations simple_form.en.yml (Latvian)

* New translations en.json (Igbo)

* New translations en.json (Thai)

* New translations en.json (Bulgarian)

* New translations en.json (Esperanto)

* New translations en.json (Irish)

* New translations en.yml (Chinese Traditional)

* New translations en.yml (Esperanto)

* New translations simple_form.en.yml (Turkish)

* New translations simple_form.en.yml (Esperanto)

* New translations en.yml (Czech)

* New translations en.json (Esperanto)

* New translations en.json (Portuguese, Brazilian)

* New translations en.yml (Portuguese, Brazilian)

* New translations en.json (Breton)

* New translations en.yml (Breton)

* New translations simple_form.en.yml (Portuguese, Brazilian)

* New translations devise.en.yml (Portuguese, Brazilian)

* New translations en.yml (Czech)

* New translations en.json (Bulgarian)

* New translations en.json (Esperanto)

* New translations en.json (Afrikaans)

* New translations en.json (Portuguese, Brazilian)

* New translations en.yml (Portuguese, Brazilian)

* New translations en.yml (Esperanto)

* New translations en.json (Breton)

* New translations en.yml (Breton)

* New translations simple_form.en.yml (Portuguese, Brazilian)

* New translations doorkeeper.en.yml (Portuguese, Brazilian)

* New translations simple_form.en.yml (Esperanto)

* New translations doorkeeper.en.yml (Esperanto)

* New translations activerecord.en.yml (Esperanto)

* New translations devise.en.yml (Esperanto)

* New translations en.json (Bulgarian)

* New translations en.json (Afrikaans)

* New translations en.json (Portuguese, Brazilian)

* New translations en.yml (Portuguese, Brazilian)

* New translations en.json (Indonesian)

* New translations en.yml (Portuguese, Brazilian)

* New translations simple_form.en.yml (Portuguese, Brazilian)

* Run `yarn manage:translations`

* Run `bundle exec i18n-tasks normalize`

* New translations en.json (Occitan)

* Run `yarn manage:translations`

Co-authored-by: Yamagishi Kazutoshi <ykzts@desire.sh>
2022-11-10 00:43:48 +09:00
Vyr Cossont 104157bd01
Add Balaibalan, Láadan, Lingua Franca Nova, Lojban, Toki Pona to language list (#20168)
* Add Balaibalan, Láadan, Lojban, Toki Pona to language list

Fixes #8995.

* Correct translated names for Lojban and Toki Pona

* Correct translated name for Balaibalan

* Add Lingua Franca Nova aka Elefen

* Disable unhelpful Rubocop checks

* Re-enable Rubocop checks at end of file
2022-11-09 15:23:52 +01:00
trwnh 029b5cd5b1
Fix GET /api/v1/admin/ip_blocks/:id (#20207) 2022-11-09 15:22:58 +01:00
Claire 5333447be0
Change account deletion requests to spread out over time (#20222) 2022-11-09 14:08:19 +01:00
Eugen Rochko e98833748e
Fix being able to spoof link verification (#20217)
- Change verification to happen in `default` queue
- Change verification worker to only be queued if there's something to do
- Add `link` tags from metadata fields to page header of profiles
2022-11-09 08:24:21 +01:00
keiya 53817294fc
Fix nginx location matching (#20198) 2022-11-09 04:12:57 +01:00
Claire dd7176a4b5
Fix redirects from /web/ discarding everything after a dot (#20148)
Fixes #20145
2022-11-09 01:30:33 +01:00
luzpaz 6ba52306f9
Fix typos (#19849)
Found via `codespell -q 3 -S ./yarn.lock,./CHANGELOG.md,./AUTHORS.md,./config/locales,./app/javascript/mastodon/locales -L ba,followings,keypair,medias,pattens,pixelx,rememberable,ro,te`
2022-11-08 17:32:03 +01:00
Christian Clauss 6f1559ed0f
CHANGELOG.md: Fix typos (#19838) 2022-11-08 17:31:52 +01:00
Sasha Sorokin d055d75172
Remove aria-pressed where it's redundant (#19912)
This commit removes aria-pressed attribute from all elements which
contents or other descriptive attributes change in active state,
effectively replacing the meaning of the button, in which case
aria-pressed, an attribute specified whether the button is currently
pressed, would create a confusion. (Spoiler: it's everywhere).

See https://github.com/mastodon/mastodon/issues/13545#issuecomment-1304886969
2022-11-08 17:31:32 +01:00
Claire d70303bba6
Add server-side route so that legacy /web/statuses/:id URLs keep being supported (#19978) 2022-11-08 17:29:14 +01:00
trwnh b1a48e05b6
Change Report category to "violation" if rule IDs are provided (#20137)
* Change Report category to "violation" if rule IDs are provided

* Fix LiteralAsCondition

* Add parentheses to conditional statement
2022-11-08 17:28:02 +01:00
Claire c476dfc725
Fix nodeinfo metadata attribute being an array instead of an object (#20114)
Fixes #20111
2022-11-08 17:26:11 +01:00
Alex Nordlund 476e74b4c4
Assign unique set of labels to k8s deployments #19703 (#19706) 2022-11-08 17:21:06 +01:00
Sheogorath f4b78028a3
chore(chart): Update appVersion in helm chart (#19653)
This patch updates the helm chart appVersion to the current release and
removes the additional definition in the image tag field, to reduce
duplication.

Since the image will automatically default to the Charts' app version
anyway and this is the more common place to specifiy application
versions for helm charts, this patch switches the prefering this field.

The reason why to use the tag field for the chart itself, seems to be
gone. Since renovatebot is no longer used.
2022-11-08 17:20:34 +01:00
Moritz Hedtke f7613febb3
helm: Fix ingress pathType (#19729) 2022-11-08 17:20:09 +01:00
Alex Nordlund fd3c482104
Roll pods to pick up db migrations even if podAnnotations is empty (#19702) 2022-11-08 17:19:14 +01:00
Alex Nordlund d3afd7a2f1
Fix helm postgresql secret (#19678)
* Revert "Fix helm chart use of Postgres Password (#19537)"

This reverts commit 6094a916b1.

* Revert "Fix PostgreSQL password reference for jobs (#19504)"

This reverts commit dae954ef11.

* Revert "Fix PostgreSQL password reference (#19502)"

This reverts commit 9bf6a8af82.

* Correct default username in postgresql auth
2022-11-08 17:18:57 +01:00
k.bigwheel (kazufumi nishida) 9358fd295d
Add postgresql password settings hint (#19112) 2022-11-08 17:18:22 +01:00
trwnh c374729225
Add sensitized to Admin::Account serializer (fix #19148) (#20094)
* Add `sensitized` to Admin::Account serializer (fix #19148)

* remove whitespace, please linter
2022-11-08 17:15:54 +01:00
Claire b2a25d446a
Merge pull request #1905 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes
2022-11-08 16:42:24 +01:00
trwnh 89e1974f30
Make account endorsements idempotent (fix #19045) (#20118)
* Make account endorsements idempotent (fix #19045)

* Accept suggestion to use exists? instead of find_by + nil check

Co-authored-by: Yamagishi Kazutoshi <ykzts@desire.sh>

* fix logic (unless, not if)

* switch to using `find_or_create_by!`

Co-authored-by: Yamagishi Kazutoshi <ykzts@desire.sh>
2022-11-08 16:39:15 +01:00
trwnh 455a754081
Fix missing cast of status and rule IDs to string (fix #19048) (#20122) 2022-11-08 16:37:41 +01:00
trwnh 68d9dcd425
Fix uncaught 500 error on invalid replies_policy (Fix #19097) (#20126) 2022-11-08 16:37:28 +01:00
Claire c989faaa62
Change Request connection logic to try both IPv6 and IPv4 when available (#20108)
Fixes #19751
2022-11-08 16:36:26 +01:00
Roni Laukkarinen 36b0ff57b7
Fix grammar (#20106) 2022-11-08 16:35:42 +01:00
Claire 9b6d6a919f [Glitch] Fix redrafting a currently-editing post not leaving edit mode
Port 782b6835f7 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-08 16:26:25 +01:00
Claire fe1b694128 [Glitch] Fix opening the language picker scrolling the single-column view to the top
Port 608343c135 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-08 15:49:09 +01:00
Zach Flanders 6eac1cfccd [Glitch] Fix spoiler buttons css not rendering correct color in light theme
Port 0beb095a4b to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-08 15:47:48 +01:00
Claire a8c854b3ea Merge branch 'main' into glitch-soc/merge-upstream 2022-11-08 15:44:57 +01:00
Claire 782b6835f7
Fix redrafting a currently-editing post not leaving edit mode (#20023) 2022-11-08 04:06:54 +01:00
James Tucker 833d9c2f1c
Improve performance by avoiding method cache busts (#19957)
Switch to monkey-patching http.rb rather than a runtime extend of each
response, so as to avoid busting the global method cache. A guard is
included that will provide developer feedback in development and test
environments should the monkey patch ever collide.
2022-11-08 04:00:27 +01:00
Claire 9f4930ec11
Add password autocomplete hints (#20071)
Fixes #20067

Our password autocomplete hints were “off” but that does not prevent current
browsers from trying to autocomplete them anyway, so use `current-password` and
`new-password` so they don't put a newly-generated password in a password
confirmation prompt, or the old password for a password renewal prompt.
2022-11-08 03:53:06 +01:00
Claire 608343c135
Fix opening the language picker scrolling the single-column view to the top (#19983)
Fixes #19915
2022-11-08 03:52:52 +01:00
Postmodern ca80beb653
Micro-optimization: use if/else instead of Array#compact and Array#min (#19906)
* Technically `if`/`else` is faster than using `[value1, value2].compact.min` to find the lesser of two values, one of which may be `nil`.
2022-11-08 03:50:47 +01:00
Zach Flanders 0beb095a4b
Fix spoiler buttons css not rendering correct color in light theme (#19960)
* Updating status__content__spoiler-link css for mastodon-light theme to ensure correct rendering precedence

* Adding focus css selector to status__content__spoiler-link mastodon-light theme

* reformatting code to match convention of having css selectors on separate lines

* fixing code format for  scss linting issue
2022-11-07 22:37:36 +01:00
Claire bbf74498f5
Fix validation error in SynchronizeFeaturedTagsCollectionWorker (#20018)
* Fix followers count not being updated when migrating follows

Fixes #19900

* Fix validation error in SynchronizeFeaturedTagsCollectionWorker

Also saves remote user's chosen case for hashtags

* Limit remote featured tags before validation
2022-11-07 22:35:53 +01:00
Claire ac219dd1f6
Merge pull request #1903 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes
2022-11-07 21:07:01 +01:00
Claire 2bc22be66c [Glitch] Add aria-expanded to content warning toggle button
Port 622f603ac7 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-07 20:04:31 +01:00
Claire be7032b9cf Merge branch 'main' into glitch-soc/merge-upstream 2022-11-07 19:53:30 +01:00
Claire 3114c826a7
Fix filter handling in status cache hydration (#19963) 2022-11-07 19:47:48 +01:00
Postmodern 106648b456
Micro-optimization: only split acct into two Strings (#19901)
* Since `acct` is split by `@` and assigned to `username` and `domain`, we only need to split `acct` into two Strings.
2022-11-07 16:17:55 +01:00
Eugen Rochko 86a80acf40
New Crowdin updates (#19771)
* New translations en.yml (Vietnamese)

* New translations en.yml (Galician)

* New translations en.yml (Icelandic)

* New translations en.yml (Japanese)

* New translations en.yml (Armenian)

* New translations en.yml (German)

* New translations en.yml (Czech)

* New translations en.yml (Chinese Simplified)

* New translations en.yml (Ido)

* New translations en.json (Esperanto)

* New translations en.yml (Turkish)

* New translations en.yml (Albanian)

* New translations en.yml (Ukrainian)

* New translations en.yml (Romanian)

* New translations en.yml (Hungarian)

* New translations en.yml (Bulgarian)

* New translations en.yml (Catalan)

* New translations en.yml (Danish)

* New translations en.yml (Greek)

* New translations en.yml (Frisian)

* New translations en.yml (Basque)

* New translations en.json (Finnish)

* New translations en.yml (Finnish)

* New translations en.yml (Irish)

* New translations en.yml (Hebrew)

* New translations en.json (Portuguese, Brazilian)

* New translations en.yml (Portuguese, Brazilian)

* New translations en.yml (Sorani (Kurdish))

* New translations en.yml (Sinhala)

* New translations en.yml (Cornish)

* New translations en.yml (Kannada)

* New translations en.yml (Asturian)

* New translations en.yml (Occitan)

* New translations en.yml (Serbian (Latin))

* New translations en.yml (Kurmanji (Kurdish))

* New translations en.yml (Corsican)

* New translations en.yml (Malayalam)

* New translations en.yml (Sardinian)

* New translations en.yml (Sanskrit)

* New translations en.yml (Kabyle)

* New translations en.yml (Taigi)

* New translations en.yml (Silesian)

* New translations en.yml (Standard Moroccan Tamazight)

* New translations simple_form.en.yml (French)

* New translations simple_form.en.yml (Kurmanji (Kurdish))

* New translations en.yml (Burmese)

* New translations en.yml (Breton)

* New translations en.yml (Tatar)

* New translations en.yml (Indonesian)

* New translations en.yml (Kazakh)

* New translations en.yml (Persian)

* New translations en.yml (Tamil)

* New translations en.yml (Spanish, Argentina)

* New translations en.yml (Spanish, Mexico)

* New translations en.yml (Bengali)

* New translations en.yml (Marathi)

* New translations en.yml (Croatian)

* New translations en.yml (Norwegian Nynorsk)

* New translations en.yml (Estonian)

* New translations en.yml (Chinese Traditional, Hong Kong)

* New translations en.json (Latvian)

* New translations en.yml (Latvian)

* New translations en.yml (Hindi)

* New translations en.yml (Malay)

* New translations en.yml (Telugu)

* New translations en.yml (English, United Kingdom)

* New translations en.yml (Welsh)

* New translations en.yml (Esperanto)

* New translations en.yml (Uyghur)

* New translations en.yml (Igbo)

* New translations en.json (Czech)

* New translations en.json (Dutch)

* New translations en.json (Hungarian)

* New translations en.yml (Hungarian)

* New translations en.yml (Dutch)

* New translations en.yml (Polish)

* New translations en.yml (Swedish)

* New translations en.json (Icelandic)

* New translations en.yml (Icelandic)

* New translations en.json (Dutch)

* New translations en.yml (Ukrainian)

* New translations en.yml (Swedish)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Simplified)

* New translations simple_form.en.yml (Irish)

* New translations simple_form.en.yml (Asturian)

* New translations devise.en.yml (Asturian)

* New translations en.json (Slovenian)

* New translations en.yml (Slovenian)

* New translations en.json (Vietnamese)

* New translations en.yml (Vietnamese)

* New translations en.yml (Asturian)

* New translations simple_form.en.yml (Vietnamese)

* New translations simple_form.en.yml (Asturian)

* New translations activerecord.en.yml (Asturian)

* New translations devise.en.yml (Asturian)

* New translations en.json (Japanese)

* New translations en.yml (Kurmanji (Kurdish))

* New translations en.json (Japanese)

* New translations en.yml (Japanese)

* New translations en.json (Vietnamese)

* New translations en.yml (Vietnamese)

* New translations simple_form.en.yml (Vietnamese)

* New translations doorkeeper.en.yml (Vietnamese)

* New translations en.json (Afrikaans)

* New translations en.json (Galician)

* New translations en.yml (Turkish)

* New translations en.json (Afrikaans)

* New translations en.yml (Afrikaans)

* New translations en.yml (Galician)

* New translations simple_form.en.yml (Afrikaans)

* New translations en.json (Albanian)

* New translations en.yml (Albanian)

* New translations en.yml (French)

* New translations en.json (Arabic)

* New translations en.yml (Arabic)

* New translations en.json (Slovenian)

* New translations simple_form.en.yml (French)

* New translations simple_form.en.yml (Albanian)

* New translations activerecord.en.yml (French)

* New translations activerecord.en.yml (Sorani (Kurdish))

* New translations devise.en.yml (French)

* New translations en.json (Norwegian Nynorsk)

* New translations en.yml (Occitan)

* New translations doorkeeper.en.yml (Norwegian Nynorsk)

* New translations simple_form.en.yml (Occitan)

* New translations doorkeeper.en.yml (Occitan)

* New translations activerecord.en.yml (Occitan)

* New translations en.yml (Spanish)

* New translations en.yml (Japanese)

* New translations en.json (Occitan)

* New translations en.json (Kurmanji (Kurdish))

* New translations simple_form.en.yml (Japanese)

* New translations simple_form.en.yml (Norwegian Nynorsk)

* New translations doorkeeper.en.yml (Norwegian Nynorsk)

* New translations doorkeeper.en.yml (Occitan)

* New translations en.yml (Thai)

* New translations en.json (Thai)

* New translations en.json (Irish)

* New translations en.json (Slovenian)

* New translations en.json (Scottish Gaelic)

* New translations en.yml (Scottish Gaelic)

* New translations en.yml (Kurmanji (Kurdish))

* New translations simple_form.en.yml (Irish)

* New translations doorkeeper.en.yml (Irish)

* New translations simple_form.en.yml (Thai)

* New translations en.json (Thai)

* New translations en.json (German)

* New translations en.yml (Spanish)

* New translations en.json (Greek)

* New translations en.json (Slovenian)

* New translations en.json (Scottish Gaelic)

* New translations en.yml (Asturian)

* New translations simple_form.en.yml (Thai)

* New translations simple_form.en.yml (Scottish Gaelic)

* New translations devise.en.yml (Asturian)

* New translations en.json (Danish)

* New translations en.json (Korean)

* New translations en.yml (Korean)

* New translations en.yml (Asturian)

* New translations simple_form.en.yml (Korean)

* New translations en.json (French)

* New translations en.json (Danish)

* New translations en.yml (Danish)

* New translations en.json (Ukrainian)

* New translations en.json (Portuguese, Brazilian)

* New translations en.yml (Portuguese, Brazilian)

* New translations en.json (Scottish Gaelic)

* New translations en.yml (Scottish Gaelic)

* New translations simple_form.en.yml (Ukrainian)

* New translations doorkeeper.en.yml (Portuguese, Brazilian)

* New translations simple_form.en.yml (Scottish Gaelic)

* New translations doorkeeper.en.yml (Scottish Gaelic)

* New translations en.json (German)

* New translations en.json (Catalan)

* New translations en.json (Danish)

* New translations en.yml (Danish)

* New translations en.json (Portuguese, Brazilian)

* New translations en.yml (Portuguese, Brazilian)

* New translations en.yml (Spanish, Mexico)

* New translations en.json (Asturian)

* New translations en.json (Occitan)

* New translations doorkeeper.en.yml (Catalan)

* New translations en.json (Scottish Gaelic)

* New translations en.yml (Scottish Gaelic)

* New translations simple_form.en.yml (Norwegian Nynorsk)

* New translations simple_form.en.yml (Scottish Gaelic)

* New translations en.json (German)

* New translations simple_form.en.yml (Norwegian Nynorsk)

* New translations en.json (Asturian)

* New translations en.yml (Asturian)

* New translations en.json (Sorani (Kurdish))

* New translations en.json (French)

* New translations en.yml (Dutch)

* New translations en.json (Welsh)

* New translations en.json (Sorani (Kurdish))

* New translations doorkeeper.en.yml (Norwegian Nynorsk)

* New translations en.json (Dutch)

* New translations en.json (French)

* New translations en.yml (Dutch)

* New translations simple_form.en.yml (Dutch)

* New translations doorkeeper.en.yml (Dutch)

* New translations en.json (Irish)

* New translations en.yml (Portuguese, Brazilian)

* New translations en.yml (German)

* New translations en.json (Arabic)

* New translations en.yml (Arabic)

* New translations en.yml (Sorani (Kurdish))

* New translations simple_form.en.yml (Arabic)

* New translations en.yml (Ukrainian)

* New translations en.json (Ukrainian)

* New translations simple_form.en.yml (Ukrainian)

* New translations doorkeeper.en.yml (Ukrainian)

* New translations activerecord.en.yml (Ukrainian)

* New translations en.json (Russian)

* New translations en.json (Bulgarian)

* New translations en.json (Hebrew)

* New translations en.json (Bulgarian)

* New translations en.json (Japanese)

* New translations en.yml (Finnish)

* New translations simple_form.en.yml (Japanese)

* New translations devise.en.yml (Finnish)

* New translations en.json (Hebrew)

* New translations en.yml (German)

* New translations en.json (Bulgarian)

* New translations en.yml (Polish)

* New translations simple_form.en.yml (Japanese)

* New translations activerecord.en.yml (Arabic)

* New translations activerecord.en.yml (Hebrew)

* New translations en.json (Bulgarian)

* New translations en.json (German)

* New translations en.json (Danish)

* New translations simple_form.en.yml (Portuguese, Brazilian)

* New translations en.json (Bulgarian)

* New translations en.json (Frisian)

* New translations en.json (Russian)

* New translations en.json (Turkish)

* New translations en.json (Ukrainian)

* New translations simple_form.en.yml (German)

* New translations simple_form.en.yml (Russian)

* New translations devise.en.yml (Frisian)

* New translations en.yml (Czech)

* New translations en.json (Bulgarian)

* New translations en.json (Czech)

* New translations en.json (Frisian)

* New translations en.json (Italian)

* New translations en.json (Polish)

* Run `yarn manage:translations`

* Run `bundle exec i18n-tasks normalize`

Co-authored-by: Yamagishi Kazutoshi <ykzts@desire.sh>
2022-11-08 00:06:48 +09:00
Claire 622f603ac7
Add aria-expanded to content warning toggle button (#19975)
Fixes #19920
2022-11-07 15:48:46 +01:00
Claire 1e1289b024
Fix crash when external auth provider has no display_name set (#19962)
Fixes #19913
2022-11-07 15:43:24 +01:00
Claire e1227457f1
Fix links to the Web UI in notifications (#19981)
Most of the old routes are broken because of the /web removal.
2022-11-07 15:42:58 +01:00
Sunny Ripert 8515bc7962
Add form element on focal point modal (#19834)
* Add form element on focal point modal

* Add type="button" for detection button
2022-11-07 15:41:42 +01:00
Claire 5925a31b78
Fix followers count not being updated when migrating follows (#19998)
Fixes #19900
2022-11-07 15:38:55 +01:00
Claire c493c967d6
Fix light theme issues with the favourite modal and some background colors (#1902)
* Fix favourite modal styling in glitch-soc light theme

* Fix unnecessary difference between glitch-soc's light theme and upstream's
2022-11-07 10:34:18 +01:00
Claire b67e0c94a6
Merge pull request #1899 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes
2022-11-07 08:31:36 +01:00
Sunny Ripert 7ba13dddfa [Glitch] Fix double button to clear emoji search input
Port 4b7f32a2a6 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-07 07:55:44 +01:00
Sunny Ripert 71e68dac4e [Glitch] Fix JavaScript console error on Getting Started column
Port ffe735344b to glitch-soc

Co-authored-by: Ilias Tsangaris <iliastsangaris@gmail.com>

Co-authored-by: Ilias Tsangaris <iliastsangaris@gmail.com>
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-07 07:54:18 +01:00
Sunny Ripert d13a2f7901 [Glitch] Fix console log error on column settings load
Port 34c269310d to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-07 07:53:20 +01:00
Claire 6c0a6097ff Merge branch 'main' into glitch-soc/merge-upstream 2022-11-07 07:50:47 +01:00
Chris Rose a70e2cd649
Tag the OTP field with autocomplete for password managers (#19946)
This is modeled on #19833, and based on the attribute values documented
in https://developer.apple.com/documentation/security/password_autofill/enabling_password_autofill_on_an_html_input_element?language=objc
2022-11-07 03:57:16 +01:00
Sunny Ripert 4b7f32a2a6
Fix double button to clear emoji search input (#19888) 2022-11-07 03:40:54 +01:00
Jeremy Kescher 02a34252ba
Add null check on application in dispute viewer (#19851) 2022-11-07 03:40:17 +01:00
Sunny Ripert ffe735344b
Fix JavaScript console error on Getting Started column (#19891)
* Fix JavaScript console error on Getting Started column

* Update app/javascript/mastodon/components/column_header.js

Co-authored-by: Ilias Tsangaris <iliastsangaris@gmail.com>

Co-authored-by: Ilias Tsangaris <iliastsangaris@gmail.com>
2022-11-07 03:40:04 +01:00
Sunny Ripert 34c269310d
Fix console log error on column settings load (#19886) 2022-11-07 03:39:48 +01:00
Claire 4cb2323458
Fix crash in legacy filter creation controller (#19878) 2022-11-07 03:38:53 +01:00
nightpool 54f0f1b9ef
Skip Webfinger cache during migrations as well (#19883) 2022-11-07 03:31:38 +01:00
Rob Petti 8c81db5a41
allow /api/v1/streaming to be used as per documentation (#19896) 2022-11-07 03:16:44 +01:00
rcombs e53fc34e9a
Set autocomplete attr for email field on signup page (#19833)
The email address will be used as the "username" for sign-in purposes, so it's the value that should be stored in password managers. We can inform the password manager of this by setting `autocomplete="email"`. Without this hint, password managers may instead store the `username` field, which isn't valid for sign-in (this happens with iCloud Keychain in Safari, for instance).
2022-11-07 03:16:10 +01:00
Claire 54101563bb
Merge pull request #1892 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes
2022-11-06 18:49:46 +01:00
Claire 21d6bc1689 Fix status cache hydration discrepancy 2022-11-06 17:29:04 +01:00
Claire 0be6da42d3 Change glitch-soc composer classes to match upstream 2022-11-06 17:29:04 +01:00
Eugen Rochko c199387558 [Glitch] Fix colors in light theme
Port 20aa8881dc to glitch-soc
2022-11-06 17:29:04 +01:00
Eugen Rochko cbfa5ad5dd [Glitch] Fix wrong colors in the high-contrast theme
Port 1c3192df6b to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-06 17:29:04 +01:00
Eugen Rochko c883799a1f [Glitch] Change design of link footer
Port 2d9a85db6e to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-06 17:29:04 +01:00
Eugen Rochko d29172a682 [Glitch] Fix missing interpolation of domain in disabled account banner in web UI
Port a442f481f8 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-06 17:29:04 +01:00
Claire b6c0ef70a2 [Glitch] Change sign-in banner to reflect disabled or moved account status
Port 312d616371 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-06 17:29:04 +01:00
Eugen Rochko 0437159056 [Glitch] Fix showing profile's featured tags on individual statuses
Port bfafb114a2 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-06 17:29:04 +01:00
Claire fa293f03fa [Glitch] Fix handling of duplicate and out-of-order notifications in WebUI
Port 7c8e2b9859 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-06 17:29:04 +01:00
Yamagishi Kazutoshi bd220c32f1
Update SECURITY.md (#19869) 2022-11-06 16:13:53 +01:00
Eugen Rochko 01e0cb1cd5 [Glitch] Add assets from Twemoji 14.0
Port e02812d5b6 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-06 10:50:23 +01:00
Sunny Ripert 8368f4857c [Glitch] Fix JavaScript console warning when loading notifications
Port 887976814a to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-06 10:47:31 +01:00
Sunny Ripert 93ccb4a29e [Glitch] Fix JavaScript console error on upload editing status
Port c95d9aab56 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-06 10:46:03 +01:00
Eugen Rochko 81334e2bfb [Glitch] Fix limited account hint referencing "your" server when logged out
Port 139ea4c981 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-06 10:45:00 +01:00
Claire 6b498fae46 [Glitch] Fix being unable to withdraw follow request when confirmation modal is disabled (#19687)
Port cbb440bbc2 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-06 10:43:18 +01:00
Claire e42875d195 [Glitch] Fix edits not being immediately reflected
Port 74d40c7d8f to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2022-11-06 10:42:15 +01:00
Claire 0ad919b192 Merge branch 'main' into glitch-soc/merge-upstream
Conflicts:
- `app/javascript/mastodon/features/compose/components/poll_form.js`:
  glitch-soc change because of having changed the default number of
  available poll options.
  Applied upstream's changes while keeping glitch-soc's default number of
  poll options.
- `public/oops.png`:
  We had a minor graphics change, probably not worth diverging from upstream.
  Took upstream version.
2022-11-06 09:50:41 +01:00
Eugen Rochko 5187e4e758
Bump version to 4.0.0rc2 (#19831) 2022-11-06 06:59:56 +01:00
Eugen Rochko 3151b260e2
Fix not using GIN index for account search queries (#19830) 2022-11-06 06:16:34 +01:00
Eugen Rochko 58fc889c6f
Update changelog for 4.0.0rc1 (#19814) 2022-11-05 23:24:07 +01:00
Eugen Rochko ca8d52c2a4
Change design of new list form in web UI (#19801) 2022-11-05 23:06:32 +01:00
Justin Thomas 18ac5f1cc8
version emoji-mart (#19715)
* version emoji-mart

* add lock file
2022-11-05 23:02:41 +01:00
Eugen Rochko b5b1a202cc
Fix missing string in admin UI (#19809) 2022-11-05 23:00:48 +01:00
Hayden c8bf6192e4
Heroku fix (#19807)
Currently building on Heroku fails with a package error for libidn11. Since Mastodon uses idn-ruby 0.1.2 we should upgrade to libidn12
2022-11-05 22:57:58 +01:00
Eugen Rochko 3a41fccc43
Change AUTHORIZED_FETCH to not block unauthenticated REST API access (#19803)
New environment variable `DISALLOW_UNAUTHENTICATED_API_ACCESS`
2022-11-05 22:56:03 +01:00
Eugen Rochko d0c9ac3919
Fix indexing scheduler trying to index when Elasticsearch is disabled (#19805)
Fix #19646
2022-11-05 22:31:52 +01:00
Eugen Rochko d54e7ee61e
Fix n+1 queries when rendering initial state JSON (#19795) 2022-11-05 21:51:01 +01:00
Moritz Hedtke c64be9758f
helm: Add documentation to run tootctl commands (#19791) 2022-11-05 21:19:25 +01:00
Eugen Rochko d1de7fb7fa
Fix rendering empty avatar in web UI (#19798) 2022-11-05 21:18:57 +01:00
Eugen Rochko a442f481f8
Fix missing interpolation of domain in disabled account banner in web UI (#19788) 2022-11-05 21:11:35 +01:00
Eugen Rochko 7c65f52692
Change design of moved account banner in web UI (#19790) 2022-11-05 21:11:24 +01:00
eai04191 30e786225e
Remove word-break:keep-all from Dismissable banner message (#19799) 2022-11-05 21:03:58 +01:00
Claire 312d616371
Change sign-in banner to reflect disabled or moved account status (#19773) 2022-11-05 18:28:13 +01:00
Alex Nordlund 0498b106c9
Add S3 existing secret to sidekiq (#19778) 2022-11-05 17:29:20 +01:00
Yarden Shoham 29604763d7
Remove broken link references to bug bounty program (#19779)
The link https://app.intigriti.com/programs/mastodon/mastodonio/detail no longer works

* Closes #19491

Signed-off-by: Yarden Shoham <hrsi88@gmail.com>

Signed-off-by: Yarden Shoham <hrsi88@gmail.com>
2022-11-05 17:27:44 +01:00
Sunny Ripert 887976814a
Fix JavaScript console warning when loading notifications (#19772) 2022-11-05 13:45:06 +01:00
Sunny Ripert c95d9aab56
Fix JavaScript console error on upload editing status (#19769) 2022-11-05 13:43:47 +01:00
Claire 9616f5bb22
Fix compose form submission reloading web interface (#19762)
* Fix compose form submission reloading web interface

Fix regression introduced by #19742

* Fix various compose form buttons being handled like submit buttons

* Fix coding style issue

* Fix missing onClick prop check
2022-11-05 13:43:37 +01:00
Claire 2f8fb49d13
Fix users not being able to change their hide_followers_count setting (#1889) 2022-11-05 11:55:25 +01:00
Eugen Rochko 1e7ea50f4c
New Crowdin updates (#19627)
* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Traditional)

* New translations en.json (Urdu (Pakistan))

* New translations en.json (Vietnamese)

* New translations en.json (Galician)

* New translations en.json (Armenian)

* New translations en.yml (Irish)

* New translations en.json (Thai)

* New translations en.json (Sinhala)

* New translations en.json (Bulgarian)

* New translations en.json (Ido)

* New translations en.json (German)

* New translations en.json (Tamil)

* New translations en.json (Esperanto)

* New translations en.json (Czech)

* New translations en.json (Dutch)

* New translations en.json (Albanian)

* New translations en.json (Japanese)

* New translations en.json (Indonesian)

* New translations en.json (Romanian)

* New translations en.json (Irish)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Afrikaans)

* New translations en.json (Arabic)

* New translations en.json (Catalan)

* New translations en.json (Danish)

* New translations en.json (Greek)

* New translations en.json (Frisian)

* New translations en.json (Basque)

* New translations en.json (Finnish)

* New translations en.json (Icelandic)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Corsican)

* New translations en.json (Kannada)

* New translations en.json (Scottish Gaelic)

* New translations en.json (Asturian)

* New translations en.json (Occitan)

* New translations en.json (Serbian (Latin))

* New translations en.json (Kurmanji (Kurdish))

* New translations en.json (Sorani (Kurdish))

* New translations en.json (Sardinian)

* New translations en.json (Breton)

* New translations en.json (Sanskrit)

* New translations en.json (Taigi)

* New translations en.json (Silesian)

* New translations en.json (Standard Moroccan Tamazight)

* New translations activerecord.en.yml (Spanish, Mexico)

* New translations en.json (Burmese)

* New translations en.json (Cornish)

* New translations en.json (Malayalam)

* New translations en.json (Persian)

* New translations en.json (Estonian)

* New translations en.json (Spanish, Argentina)

* New translations en.json (Spanish, Mexico)

* New translations en.json (Bengali)

* New translations en.json (Marathi)

* New translations en.json (Croatian)

* New translations en.json (Norwegian Nynorsk)

* New translations en.json (Kazakh)

* New translations en.json (Latvian)

* New translations en.json (Tatar)

* New translations en.json (Hindi)

* New translations en.json (Malay)

* New translations en.json (Telugu)

* New translations en.json (English, United Kingdom)

* New translations en.json (Welsh)

* New translations en.json (Uyghur)

* New translations en.json (Chinese Traditional, Hong Kong)

* New translations en.json (Japanese)

* New translations en.json (Finnish)

* New translations en.json (Irish)

* New translations en.yml (Irish)

* New translations en.json (Portuguese)

* New translations en.json (Chinese Simplified)

* New translations en.json (Spanish, Argentina)

* New translations en.json (Irish)

* New translations en.json (Irish)

* New translations doorkeeper.en.yml (Irish)

* New translations activerecord.en.yml (Irish)

* New translations devise.en.yml (Irish)

* New translations en.json (Greek)

* New translations en.json (Irish)

* New translations en.json (Korean)

* New translations en.yml (Korean)

* New translations en.json (Chinese Traditional)

* New translations en.json (Galician)

* New translations en.json (French)

* New translations en.yml (French)

* New translations en.json (Italian)

* New translations en.json (Vietnamese)

* New translations en.json (Latvian)

* New translations simple_form.en.yml (Korean)

* New translations en.json (Esperanto)

* New translations en.json (Albanian)

* New translations en.json (Indonesian)

* New translations en.json (Icelandic)

* New translations en.yml (Indonesian)

* New translations en.json (Norwegian Nynorsk)

* New translations en.yml (Norwegian Nynorsk)

* Run `yarn manage:translations`

* Run `bundle exec i18n-tasks normalize`

* New translations en.json (Slovenian)

* New translations en.json (Turkish)

* New translations en.json (Vietnamese)

* New translations en.yml (Norwegian Nynorsk)

* New translations en.json (Kurmanji (Kurdish))

* New translations en.json (German)

* New translations simple_form.en.yml (Finnish)

* New translations en.json (Hungarian)

* New translations en.yml (Hungarian)

* New translations en.json (Breton)

* New translations en.json (Dutch)

* New translations en.json (Spanish)

* New translations simple_form.en.yml (French)

* New translations simple_form.en.yml (Czech)

* New translations simple_form.en.yml (Norwegian)

* New translations simple_form.en.yml (Hungarian)

* New translations en.json (French)

* New translations simple_form.en.yml (Italian)

* New translations simple_form.en.yml (Japanese)

* New translations simple_form.en.yml (Georgian)

* New translations simple_form.en.yml (Korean)

* New translations simple_form.en.yml (Portuguese)

* New translations simple_form.en.yml (Russian)

* New translations simple_form.en.yml (Slovak)

* New translations simple_form.en.yml (Slovenian)

* New translations simple_form.en.yml (Albanian)

* New translations simple_form.en.yml (Serbian (Cyrillic))

* New translations simple_form.en.yml (Swedish)

* New translations simple_form.en.yml (Turkish)

* New translations simple_form.en.yml (Hebrew)

* New translations simple_form.en.yml (Armenian)

* New translations simple_form.en.yml (Finnish)

* New translations simple_form.en.yml (Afrikaans)

* New translations en.json (Catalan)

* New translations simple_form.en.yml (Dutch)

* New translations simple_form.en.yml (Polish)

* New translations simple_form.en.yml (Basque)

* New translations simple_form.en.yml (Romanian)

* New translations simple_form.en.yml (French)

* New translations simple_form.en.yml (Spanish)

* New translations simple_form.en.yml (Arabic)

* New translations simple_form.en.yml (Bulgarian)

* New translations simple_form.en.yml (Catalan)

* New translations simple_form.en.yml (Danish)

* New translations simple_form.en.yml (German)

* New translations simple_form.en.yml (Greek)

* New translations simple_form.en.yml (Frisian)

* New translations simple_form.en.yml (Indonesian)

* New translations simple_form.en.yml (Portuguese, Brazilian)

* New translations simple_form.en.yml (Icelandic)

* New translations simple_form.en.yml (Galician)

* New translations simple_form.en.yml (Chinese Simplified)

* New translations simple_form.en.yml (Chinese Traditional)

* New translations simple_form.en.yml (Ukrainian)

* New translations en.json (Ukrainian)

* New translations simple_form.en.yml (Sinhala)

* New translations simple_form.en.yml (Vietnamese)

* New translations simple_form.en.yml (Persian)

* New translations simple_form.en.yml (Tamil)

* New translations simple_form.en.yml (Corsican)

* New translations simple_form.en.yml (Scottish Gaelic)

* New translations simple_form.en.yml (Asturian)

* New translations simple_form.en.yml (Occitan)

* New translations simple_form.en.yml (Serbian (Latin))

* New translations simple_form.en.yml (Kurmanji (Kurdish))

* New translations simple_form.en.yml (Sorani (Kurdish))

* New translations simple_form.en.yml (Sardinian)

* New translations simple_form.en.yml (Breton)

* New translations simple_form.en.yml (Kabyle)

* New translations simple_form.en.yml (Ido)

* New translations simple_form.en.yml (Standard Moroccan Tamazight)

* New translations simple_form.en.yml (Malayalam)

* New translations simple_form.en.yml (Spanish, Argentina)

* New translations simple_form.en.yml (Estonian)

* New translations simple_form.en.yml (Spanish, Mexico)

* New translations simple_form.en.yml (Bengali)

* New translations simple_form.en.yml (Thai)

* New translations simple_form.en.yml (Croatian)

* New translations simple_form.en.yml (Norwegian Nynorsk)

* New translations simple_form.en.yml (Kazakh)

* New translations simple_form.en.yml (Latvian)

* New translations simple_form.en.yml (Tatar)

* New translations simple_form.en.yml (Welsh)

* New translations simple_form.en.yml (Esperanto)

* New translations simple_form.en.yml (Chinese Traditional, Hong Kong)

* New translations en.json (Persian)

* New translations simple_form.en.yml (Hungarian)

* New translations simple_form.en.yml (Portuguese)

* New translations simple_form.en.yml (Kurmanji (Kurdish))

* New translations simple_form.en.yml (Norwegian Nynorsk)

* New translations simple_form.en.yml (Finnish)

* New translations simple_form.en.yml (Italian)

* New translations en.yml (Catalan)

* New translations simple_form.en.yml (Catalan)

* New translations simple_form.en.yml (Ukrainian)

* New translations en.json (Irish)

* New translations simple_form.en.yml (Dutch)

* New translations en.json (Ukrainian)

* New translations activerecord.en.yml (Irish)

* New translations en.json (Polish)

* New translations simple_form.en.yml (Chinese Simplified)

* New translations simple_form.en.yml (Greek)

* New translations simple_form.en.yml (Hungarian)

* New translations simple_form.en.yml (Slovenian)

* New translations simple_form.en.yml (Asturian)

* New translations en.yml (Dutch)

* New translations simple_form.en.yml (Dutch)

* New translations en.yml (Swedish)

* New translations simple_form.en.yml (Polish)

* New translations simple_form.en.yml (Chinese Traditional)

* New translations en.yml (Dutch)

* New translations en.json (Swedish)

* New translations en.yml (Swedish)

* New translations simple_form.en.yml (Swedish)

* New translations en.json (Swedish)

* New translations en.yml (Swedish)

* New translations simple_form.en.yml (Swedish)

* New translations doorkeeper.en.yml (Swedish)

* New translations activerecord.en.yml (Swedish)

* New translations en.json (Swedish)

* New translations en.yml (Swedish)

* New translations simple_form.en.yml (Swedish)

* New translations en.json (Swedish)

* New translations en.yml (Swedish)

* New translations simple_form.en.yml (Vietnamese)

* New translations simple_form.en.yml (French)

* New translations simple_form.en.yml (Swedish)

* New translations simple_form.en.yml (Spanish, Argentina)

* New translations simple_form.en.yml (Vietnamese)

* New translations en.json (Afrikaans)

* New translations en.yml (Afrikaans)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Norwegian Nynorsk)

* New translations simple_form.en.yml (Afrikaans)

* New translations simple_form.en.yml (Japanese)

* New translations simple_form.en.yml (Korean)

* New translations en.json (Norwegian Nynorsk)

* New translations en.yml (Swedish)

* New translations en.json (Norwegian Nynorsk)

* New translations en.json (Polish)

* New translations en.json (Swedish)

* New translations en.yml (Swedish)

* New translations simple_form.en.yml (Icelandic)

* New translations en.json (Czech)

* Run `yarn manage:translations`

* Run `bundle exec i18n-tasks normalize`

Co-authored-by: Yamagishi Kazutoshi <ykzts@desire.sh>
2022-11-05 19:54:26 +09:00
prplecake 34ba7612d1
Fix 'App settings' label visible in sidebar on mobile UI (#1888) 2022-11-05 08:12:04 +01:00
Eugen Rochko c4b92b1aee
Fix n+1 query during status removal (#19753) 2022-11-05 00:09:52 +01:00
Claire bb89f83cc0
Fix additional issues with status cache hydration (#19747)
* Spare one SQL query when hydrating polls

* Improve tests

* Fix more discrepancies

* Fix possible crash when the status has no application set
2022-11-04 20:01:33 +01:00
Claire 03b991de6c
Fix various issues with store hydration (#19746)
- Improve tests
- Fix possible crash when application of a reblogged post isn't set
- Fix discrepancies around favourited and reblogged attributes
- Fix discrepancies around pinned attribute
- Fix polls not being hydrated
2022-11-04 19:33:16 +01:00
Sunny Ripert 0165449e3a
A11y: Explicit <form> element around compose area (#19742) 2022-11-04 17:08:08 +01:00
Claire c2170991c7
Fix reblogs being discarded after the reblogged status (#19731) 2022-11-04 16:31:44 +01:00
Eugen Rochko e02812d5b6
Add assets from Twemoji 14.0 (#19733) 2022-11-04 16:08:41 +01:00
Eugen Rochko b1a219552e
Fix featured tags not saving preferred casing (#19732) 2022-11-04 16:08:29 +01:00
Jeong Arm f002878c95
Make word-break: keep-all for dismissable banner (#19719) 2022-11-04 16:04:25 +01:00
Eugen Rochko 5f9e47be34
Add caching for payload serialization during fan-out (#19642) 2022-11-04 13:21:06 +01:00
Claire b8f6f03956
Fix /users/:username/statuses/:id leading to a soft 404 in web app (#19724) 2022-11-04 13:19:57 +01:00
Claire 4fb0aae636
Change mentions of blocked users to not be processed (#19725)
Fixes #19698
2022-11-04 13:19:12 +01:00
Eugen Rochko 20aa8881dc
Fix colors in light theme (#19714) 2022-11-04 02:32:26 +01:00
Eugen Rochko 139ea4c981
Fix limited account hint referencing "your" server when logged out (#19711) 2022-11-04 02:28:37 +01:00
Eugen Rochko bfafb114a2
Fix showing profile's featured tags on individual statuses (#19712) 2022-11-04 02:28:25 +01:00
Eugen Rochko 1c3192df6b
Fix wrong colors in the high-contrast theme (#19708) 2022-11-04 02:28:14 +01:00
Eugen Rochko 5825402ed5
Fix design of verified links in web UI (#19709) 2022-11-04 02:28:00 +01:00
Claire 7c8e2b9859
Fix handling of duplicate and out-of-order notifications in WebUI (#19693)
* Fix handling of duplicate notifications from streaming server

* Fix handling of duplicate and out-of-order notifications when polling/expanding

Fixes #19615
2022-11-04 00:14:39 +01:00
SJang1 053dac2afa
Remove meta tag for official iOS app (#19656) 2022-11-04 00:13:07 +01:00
Claire 9387beb3b3
Change flaky AccountSearchService test (#19650) 2022-11-03 23:12:08 +01:00
Claire 1dca08b76f
Fix admin action logs page (#19649)
* Add tests

* Fix crash when trying to display orphaned action logs

* Add migration for older admin action logs
2022-11-03 16:06:42 +01:00
Claire cbb440bbc2
Fix being unable to withdraw follow request when confirmation modal is disabled (#19687)
* Fix being unable to withdraw follow request when unfollow confirmation modal is disabled

Fixes #19569

* Fix “unfollow” being inadequately used for withdrawing follow requests from account card
2022-11-03 16:05:39 +01:00
Claire 125322718b
Fix inaccurate admin log entry for re-sending confirmation e-mails (#19674)
Fixes #19593
2022-11-02 18:50:21 +01:00
Claire 74d40c7d8f
Fix edits not being immediately reflected (#19673)
Fixes #19546
2022-11-02 18:09:39 +01:00
Claire e0eb39d41b
Fix bookmark import stopping at the first failure (#19669)
Fixes #19389
2022-11-02 16:38:23 +01:00
Claire e91418436a
Fix mastodon:setup not setting the admin's role properly (#19670)
* Fix mastodon:setup not setting the admin's role properly

* Set contact username when creating admin account in mastodon:setup
2022-11-02 16:35:21 +01:00
Claire cb27d89997
Change migration to migrate admins to Owner role rather than Admin role (#19671) 2022-11-02 16:34:47 +01:00
prplecake f359b15303
Allow number of trending hashtags to be customizable (#1884) 2022-11-02 09:20:47 +01:00
txt-file 0f5e6dd02b
Add support for AVIF uploads (#19647) 2022-11-01 22:08:41 +01:00
prplecake 56eb1da0f5
Fix CharacterCount in vanilla UI (#1883) 2022-11-01 18:06:07 +01:00
Eugen Rochko ae07cfb868
Add support for HEIC uploads (#19618) 2022-11-01 16:26:25 +01:00
Claire 6804228fdf
Fix N+1 on mentions in PushUpdateWorker (#19637) 2022-11-01 16:03:51 +01:00
Eugen Rochko 15bae3e0e4
Change post-processing to be deferred only for large media types (#19617) 2022-11-01 15:27:58 +01:00
pea-sys c68e6b52d9
png optimization(loss less) (#19630) 2022-11-01 15:06:52 +01:00
Jeong Arm 55f54be23c
Add translatable scripts (js) (#19624) 2022-11-01 13:05:39 +01:00
Eugen Rochko d0ba77047e
Change max. thumbnail dimensions to 640x360px (360p) (#19619) 2022-11-01 13:01:39 +01:00
Claire 03d9618595
Fix UserCleanupScheduler crash when an unconfirmed account has a moderation note (#19629)
Fixes #19109
2022-11-01 12:59:23 +01:00
Eugen Rochko fea142fb9a
New Crowdin updates (#19517)
* New translations en.json (Persian)

* New translations en.json (Spanish, Argentina)

* New translations simple_form.en.yml (Arabic)

* New translations activerecord.en.yml (Slovenian)

* New translations activerecord.en.yml (Turkish)

* New translations en.json (Persian)

* New translations en.yml (Persian)

* New translations activerecord.en.yml (Spanish)

* New translations en.json (Czech)

* New translations en.json (Arabic)

* New translations en.yml (Arabic)

* New translations en.json (Catalan)

* New translations en.json (Greek)

* New translations en.json (Basque)

* New translations en.yml (Basque)

* New translations en.json (Polish)

* New translations en.json (Chinese Traditional)

* New translations en.json (Latvian)

* New translations simple_form.en.yml (Basque)

* New translations activerecord.en.yml (Greek)

* New translations activerecord.en.yml (Basque)

* New translations activerecord.en.yml (Polish)

* New translations en.yml (German)

* New translations en.json (Vietnamese)

* New translations en.json (Kurmanji (Kurdish))

* New translations simple_form.en.yml (German)

* New translations en.json (Kurmanji (Kurdish))

* New translations en.json (Romanian)

* New translations en.json (Chinese Traditional)

* New translations simple_form.en.yml (Chinese Traditional)

* New translations activerecord.en.yml (Afrikaans)

* New translations en.json (German)

* New translations en.json (Romanian)

* New translations en.json (Afrikaans)

* New translations en.json (German)

* New translations en.json (Japanese)

* New translations en.yml (Japanese)

* New translations simple_form.en.yml (Japanese)

* New translations activerecord.en.yml (Japanese)

* New translations en.yml (German)

* New translations en.yml (Portuguese, Brazilian)

* New translations simple_form.en.yml (German)

* New translations simple_form.en.yml (Portuguese, Brazilian)

* New translations activerecord.en.yml (German)

* New translations activerecord.en.yml (Portuguese, Brazilian)

* New translations en.json (Polish)

* New translations simple_form.en.yml (Portuguese, Brazilian)

* New translations en.yml (German)

* New translations en.json (German)

* New translations en.json (Italian)

* New translations en.json (Portuguese)

* New translations simple_form.en.yml (German)

* New translations en.json (Bulgarian)

* New translations en.json (Chinese Traditional)

* New translations en.json (Danish)

* New translations en.json (Finnish)

* New translations en.json (Dutch)

* New translations en.json (Danish)

* New translations simple_form.en.yml (Danish)

* New translations activerecord.en.yml (Danish)

* New translations en.json (Dutch)

* New translations en.json (Chinese Traditional)

* New translations en.yml (Chinese Traditional)

* New translations simple_form.en.yml (Chinese Traditional)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Traditional)

* New translations en.yml (Chinese Traditional)

* New translations simple_form.en.yml (Chinese Traditional)

* New translations doorkeeper.en.yml (Chinese Traditional)

* New translations devise.en.yml (Chinese Traditional)

* New translations en.json (Chinese Traditional)

* New translations en.yml (Chinese Traditional)

* New translations en.yml (Spanish, Argentina)

* New translations doorkeeper.en.yml (Chinese Traditional)

* New translations en.json (Korean)

* New translations en.yml (Korean)

* New translations en.json (Chinese Traditional)

* New translations en.yml (Chinese Traditional)

* New translations simple_form.en.yml (Chinese Traditional)

* New translations en.json (Chinese Traditional)

* New translations en.yml (Chinese Traditional)

* New translations simple_form.en.yml (Chinese Traditional)

* New translations doorkeeper.en.yml (Chinese Traditional)

* New translations devise.en.yml (Chinese Traditional)

* New translations en.json (Japanese)

* New translations en.yml (Japanese)

* New translations en.json (Chinese Simplified)

* New translations en.json (French)

* New translations en.yml (French)

* New translations simple_form.en.yml (French)

* New translations en.yml (German)

* New translations en.json (French)

* New translations en.json (Afrikaans)

* New translations en.yml (Afrikaans)

* New translations en.json (Kabyle)

* New translations en.yml (Kabyle)

* New translations simple_form.en.yml (Kabyle)

* New translations en.yml (Czech)

* New translations en.json (German)

* New translations en.json (French)

* New translations en.yml (Catalan)

* New translations en.yml (Kurmanji (Kurdish))

* New translations simple_form.en.yml (Kurmanji (Kurdish))

* New translations activerecord.en.yml (Kurmanji (Kurdish))

* New translations en.yml (German)

* New translations en.json (Bulgarian)

* New translations en.json (German)

* New translations en.yml (Italian)

* New translations en.yml (German)

* New translations en.json (German)

* New translations en.yml (Greek)

* New translations en.json (Hungarian)

* New translations en.yml (Hungarian)

* New translations en.yml (Portuguese)

* New translations en.yml (Vietnamese)

* New translations en.yml (German)

* New translations en.json (German)

* New translations en.yml (Polish)

* New translations en.yml (Latvian)

* New translations en.yml (German)

* New translations en.json (German)

* New translations en.yml (Turkish)

* New translations en.yml (Ukrainian)

* New translations simple_form.en.yml (German)

* New translations en.json (German)

* New translations en.yml (German)

* New translations en.json (German)

* New translations en.json (Asturian)

* New translations simple_form.en.yml (German)

* New translations doorkeeper.en.yml (German)

* New translations en.json (German)

* New translations en.yml (German)

* New translations en.json (German)

* New translations en.json (Basque)

* New translations en.json (Chinese Simplified)

* New translations en.json (Basque)

* New translations en.yml (Basque)

* New translations en.json (Slovenian)

* New translations simple_form.en.yml (Basque)

* New translations en.yml (Spanish)

* New translations en.json (Spanish)

* New translations en.yml (Basque)

* New translations activerecord.en.yml (Spanish)

* New translations en.yml (German)

* New translations en.json (German)

* New translations en.yml (Ukrainian)

* New translations en.json (Ukrainian)

* New translations simple_form.en.yml (German)

* New translations simple_form.en.yml (Ukrainian)

* New translations activerecord.en.yml (Ukrainian)

* New translations en.json (German)

* New translations en.yml (Ukrainian)

* New translations en.json (Slovenian)

* New translations en.json (Ukrainian)

* New translations simple_form.en.yml (German)

* New translations simple_form.en.yml (Ukrainian)

* New translations doorkeeper.en.yml (Ukrainian)

* New translations en.json (German)

* New translations en.json (Esperanto)

* New translations en.yml (Dutch)

* New translations simple_form.en.yml (Dutch)

* New translations doorkeeper.en.yml (Dutch)

* New translations en.yml (Japanese)

* New translations simple_form.en.yml (Japanese)

* New translations en.json (Japanese)

* New translations en.yml (Japanese)

* New translations en.yml (Dutch)

* New translations simple_form.en.yml (Dutch)

* New translations simple_form.en.yml (Japanese)

* New translations en.json (Japanese)

* New translations en.yml (Japanese)

* New translations en.yml (German)

* New translations en.json (German)

* New translations en.json (Japanese)

* New translations en.json (Slovenian)

* New translations en.yml (Slovenian)

* New translations en.yml (German)

* New translations en.json (Japanese)

* New translations en.json (Indonesian)

* New translations simple_form.en.yml (German)

* New translations en.yml (German)

* New translations en.json (German)

* New translations en.json (Indonesian)

* New translations en.yml (Russian)

* New translations en.yml (Indonesian)

* New translations simple_form.en.yml (Indonesian)

* New translations en.json (Burmese)

* New translations en.yml (Burmese)

* New translations simple_form.en.yml (Burmese)

* New translations activerecord.en.yml (Burmese)

* New translations devise.en.yml (Burmese)

* New translations doorkeeper.en.yml (Burmese)

* New translations en.yml (German)

* New translations en.json (German)

* New translations en.yml (Indonesian)

* New translations simple_form.en.yml (Indonesian)

* New translations activerecord.en.yml (Indonesian)

* New translations en.json (Burmese)

* New translations en.json (German)

* New translations en.json (Indonesian)

* New translations en.json (Swedish)

* New translations en.json (Icelandic)

* New translations en.yml (Indonesian)

* New translations simple_form.en.yml (Indonesian)

* New translations en.json (Hungarian)

* New translations en.json (German)

* New translations en.json (Icelandic)

* New translations en.yml (Icelandic)

* New translations en.json (Scottish Gaelic)

* New translations en.yml (Scottish Gaelic)

* New translations en.json (German)

* New translations en.yml (Arabic)

* New translations en.json (Hindi)

* New translations en.json (Scottish Gaelic)

* New translations simple_form.en.yml (Arabic)

* New translations simple_form.en.yml (Scottish Gaelic)

* New translations activerecord.en.yml (Scottish Gaelic)

* New translations devise.en.yml (Scottish Gaelic)

* New translations activerecord.en.yml (Danish)

* New translations en.json (German)

* New translations en.json (Scottish Gaelic)

* New translations en.json (German)

* New translations en.json (Persian)

* New translations en.yml (Persian)

* New translations en.json (Persian)

* New translations activerecord.en.yml (Persian)

* New translations en.json (Igbo)

* New translations en.yml (Igbo)

* New translations simple_form.en.yml (Igbo)

* New translations activerecord.en.yml (Igbo)

* New translations devise.en.yml (Igbo)

* New translations doorkeeper.en.yml (Igbo)

* New translations en.json (Korean)

* New translations en.yml (Korean)

* New translations en.json (Spanish, Argentina)

* New translations simple_form.en.yml (Korean)

* New translations en.json (Spanish, Argentina)

* New translations en.json (Japanese)

* New translations simple_form.en.yml (Japanese)

* New translations en.json (Igbo)

* New translations en.json (Japanese)

* New translations en.yml (Japanese)

* New translations en.yml (Japanese)

* New translations simple_form.en.yml (Japanese)

* New translations en.json (Galician)

* New translations en.yml (Galician)

* New translations simple_form.en.yml (Kurmanji (Kurdish))

* Run `yarn manage:translations`

* Run `bundle exec i18n-tasks normalize`

Co-authored-by: Yamagishi Kazutoshi <ykzts@desire.sh>
2022-11-01 18:42:04 +09:00
Claire bb1ef11c30
Change featured hashtag deletion to be done synchronously (#19590) 2022-10-31 16:31:44 +01:00
Eugen Rochko 2d9a85db6e
Change design of link footer (#19562) 2022-10-31 13:06:17 +01:00
702 changed files with 15735 additions and 7799 deletions

View file

@ -279,6 +279,10 @@ MAX_POLL_OPTION_CHARS=100
# Only relevant when elasticsearch is installed
# MAX_SEARCH_RESULTS=20
# Maximum hashtags to display
# Customize the number of hashtags shown in 'Explore'
# MAX_TRENDING_TAGS=10
# Maximum custom emoji file sizes
# If undefined or smaller than MAX_EMOJI_SIZE, the value
# of MAX_EMOJI_SIZE will be used for MAX_REMOTE_EMOJI_SIZE

View file

@ -3,6 +3,3 @@ contact_links:
- name: GitHub Discussions
url: https://github.com/mastodon/mastodon/discussions
about: Please ask and answer questions here.
- name: Bug Bounty Program
url: https://app.intigriti.com/programs/mastodon/mastodonio/detail
about: Please report security vulnerabilities here.

View file

@ -1,8 +1,8 @@
ffmpeg
libicu[0-9][0-9]
libicu-dev
libidn11
libidn11-dev
libidn12
libidn-dev
libpq-dev
libxdamage1
libxfixes3

View file

@ -13,7 +13,7 @@ Some of the features in this release have been funded through the [NGI0 Discover
- **Add ability to follow hashtags** ([Gargron](https://github.com/mastodon/mastodon/pull/18809), [Gargron](https://github.com/mastodon/mastodon/pull/18862), [Gargron](https://github.com/mastodon/mastodon/pull/19472), [noellabo](https://github.com/mastodon/mastodon/pull/18924))
- Add ability to filter individual posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18945))
- **Add ability to translate posts** ([Gargron](https://github.com/mastodon/mastodon/pull/19218), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19433), [Gargron](https://github.com/mastodon/mastodon/pull/19453), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19434), [Gargron](https://github.com/mastodon/mastodon/pull/19388), [ykzts](https://github.com/mastodon/mastodon/pull/19244), [Gargron](https://github.com/mastodon/mastodon/pull/19245))
- Add featured tags to web UI ([noellabo](https://github.com/mastodon/mastodon/pull/19408), [noellabo](https://github.com/mastodon/mastodon/pull/19380), [noellabo](https://github.com/mastodon/mastodon/pull/19358), [noellabo](https://github.com/mastodon/mastodon/pull/19409), [Gargron](https://github.com/mastodon/mastodon/pull/19382), [ykzts](https://github.com/mastodon/mastodon/pull/19418), [noellabo](https://github.com/mastodon/mastodon/pull/19403), [noellabo](https://github.com/mastodon/mastodon/pull/19404), [Gargron](https://github.com/mastodon/mastodon/pull/19398))
- Add featured tags to web UI ([noellabo](https://github.com/mastodon/mastodon/pull/19408), [noellabo](https://github.com/mastodon/mastodon/pull/19380), [noellabo](https://github.com/mastodon/mastodon/pull/19358), [noellabo](https://github.com/mastodon/mastodon/pull/19409), [Gargron](https://github.com/mastodon/mastodon/pull/19382), [ykzts](https://github.com/mastodon/mastodon/pull/19418), [noellabo](https://github.com/mastodon/mastodon/pull/19403), [noellabo](https://github.com/mastodon/mastodon/pull/19404), [Gargron](https://github.com/mastodon/mastodon/pull/19398), [Gargron](https://github.com/mastodon/mastodon/pull/19712))
- **Add support for language preferences for trending statuses and links** ([Gargron](https://github.com/mastodon/mastodon/pull/18288), [Gargron](https://github.com/mastodon/mastodon/pull/19349), [ykzts](https://github.com/mastodon/mastodon/pull/19335))
- Previously, you could only see trends in your current language
- For less popular languages, that meant empty trends
@ -23,9 +23,10 @@ Some of the features in this release have been funded through the [NGI0 Discover
- Add `noopener` to links to remote profiles in web UI ([shleeable](https://github.com/mastodon/mastodon/pull/19014))
- Add warning for sensitive audio posts in web UI ([rgroothuijsen](https://github.com/mastodon/mastodon/pull/17885))
- Add language attribute to posts in web UI ([tribela](https://github.com/mastodon/mastodon/pull/18544))
- Add meta tag for official iOS app ([Gargron](https://github.com/mastodon/mastodon/pull/16599))
- Add support for uploading WebP files ([Saiv46](https://github.com/mastodon/mastodon/pull/18506))
- Add support for uploading `audio/vnd.wave` files ([tribela](https://github.com/mastodon/mastodon/pull/18737))
- Add support for uploading AVIF files ([txt-file](https://github.com/mastodon/mastodon/pull/19647))
- Add support for uploading HEIC files ([Gargron](https://github.com/mastodon/mastodon/pull/19618))
- Add more debug information when processing remote accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15605), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19209))
- **Add retention policy for cached content and media** ([Gargron](https://github.com/mastodon/mastodon/pull/19232), [zunda](https://github.com/mastodon/mastodon/pull/19478), [Gargron](https://github.com/mastodon/mastodon/pull/19458), [Gargron](https://github.com/mastodon/mastodon/pull/19248))
- Set for how long remote posts or media should be cached on your server
@ -49,12 +50,15 @@ Some of the features in this release have been funded through the [NGI0 Discover
- Add `EMAIL_DOMAIN_LISTS_APPLY_AFTER_CONFIRMATION` environment variable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18642))
- Add `IP_RETENTION_PERIOD` and `SESSION_RETENTION_PERIOD` environment variables ([kescherCode](https://github.com/mastodon/mastodon/pull/18757))
- Add `http_hidden_proxy` environment variable ([tribela](https://github.com/mastodon/mastodon/pull/18427))
- Add caching for payload serialization during fan-out ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/19637), [Gargron](https://github.com/mastodon/mastodon/pull/19642), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19746), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19747))
- Add assets from Twemoji 14.0 ([Gargron](https://github.com/mastodon/mastodon/pull/19733))
- Add reputation and followers score boost to SQL-only account search ([Gargron](https://github.com/mastodon/mastodon/pull/19251))
### Changed
- **Change brand color and logotypes** ([Gargron](https://github.com/mastodon/mastodon/pull/18592), [Gargron](https://github.com/mastodon/mastodon/pull/18639), [Gargron](https://github.com/mastodon/mastodon/pull/18691), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/18634), [Gargron](https://github.com/mastodon/mastodon/pull/19254), [mayaeh](https://github.com/mastodon/mastodon/pull/18710))
- **Change post editing to be enabled in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/19103))
- **Change web UI to work for logged-out users** ([Gargron](https://github.com/mastodon/mastodon/pull/18961), [Gargron](https://github.com/mastodon/mastodon/pull/19250), [Gargron](https://github.com/mastodon/mastodon/pull/19294), [Gargron](https://github.com/mastodon/mastodon/pull/19306), [Gargron](https://github.com/mastodon/mastodon/pull/19315), [ykzts](https://github.com/mastodon/mastodon/pull/19322), [Gargron](https://github.com/mastodon/mastodon/pull/19412), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19437), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19415), [Gargron](https://github.com/mastodon/mastodon/pull/19348), [Gargron](https://github.com/mastodon/mastodon/pull/19295), [Gargron](https://github.com/mastodon/mastodon/pull/19422), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19414), [Gargron](https://github.com/mastodon/mastodon/pull/19319), [Gargron](https://github.com/mastodon/mastodon/pull/19345), [Gargron](https://github.com/mastodon/mastodon/pull/19310), [Gargron](https://github.com/mastodon/mastodon/pull/19301), [Gargron](https://github.com/mastodon/mastodon/pull/19423), [ykzts](https://github.com/mastodon/mastodon/pull/19471), [ykzts](https://github.com/mastodon/mastodon/pull/19333), [ykzts](https://github.com/mastodon/mastodon/pull/19337), [ykzts](https://github.com/mastodon/mastodon/pull/19272), [ykzts](https://github.com/mastodon/mastodon/pull/19468), [Gargron](https://github.com/mastodon/mastodon/pull/19466), [Gargron](https://github.com/mastodon/mastodon/pull/19457), [Gargron](https://github.com/mastodon/mastodon/pull/19426), [Gargron](https://github.com/mastodon/mastodon/pull/19427), [Gargron](https://github.com/mastodon/mastodon/pull/19421), [Gargron](https://github.com/mastodon/mastodon/pull/19417), [Gargron](https://github.com/mastodon/mastodon/pull/19413), [Gargron](https://github.com/mastodon/mastodon/pull/19397), [Gargron](https://github.com/mastodon/mastodon/pull/19387), [Gargron](https://github.com/mastodon/mastodon/pull/19396), [Gargron](https://github.com/mastodon/mastodon/pull/19385), [ykzts](https://github.com/mastodon/mastodon/pull/19334), [ykzts](https://github.com/mastodon/mastodon/pull/19329), [Gargron](https://github.com/mastodon/mastodon/pull/19324), [Gargron](https://github.com/mastodon/mastodon/pull/19318), [Gargron](https://github.com/mastodon/mastodon/pull/19316), [Gargron](https://github.com/mastodon/mastodon/pull/19263), [trwnh](https://github.com/mastodon/mastodon/pull/19305), [ykzts](https://github.com/mastodon/mastodon/pull/19273))
- **Change web UI to work for logged-out users** ([Gargron](https://github.com/mastodon/mastodon/pull/18961), [Gargron](https://github.com/mastodon/mastodon/pull/19250), [Gargron](https://github.com/mastodon/mastodon/pull/19294), [Gargron](https://github.com/mastodon/mastodon/pull/19306), [Gargron](https://github.com/mastodon/mastodon/pull/19315), [ykzts](https://github.com/mastodon/mastodon/pull/19322), [Gargron](https://github.com/mastodon/mastodon/pull/19412), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19437), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19415), [Gargron](https://github.com/mastodon/mastodon/pull/19348), [Gargron](https://github.com/mastodon/mastodon/pull/19295), [Gargron](https://github.com/mastodon/mastodon/pull/19422), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19414), [Gargron](https://github.com/mastodon/mastodon/pull/19319), [Gargron](https://github.com/mastodon/mastodon/pull/19345), [Gargron](https://github.com/mastodon/mastodon/pull/19310), [Gargron](https://github.com/mastodon/mastodon/pull/19301), [Gargron](https://github.com/mastodon/mastodon/pull/19423), [ykzts](https://github.com/mastodon/mastodon/pull/19471), [ykzts](https://github.com/mastodon/mastodon/pull/19333), [ykzts](https://github.com/mastodon/mastodon/pull/19337), [ykzts](https://github.com/mastodon/mastodon/pull/19272), [ykzts](https://github.com/mastodon/mastodon/pull/19468), [Gargron](https://github.com/mastodon/mastodon/pull/19466), [Gargron](https://github.com/mastodon/mastodon/pull/19457), [Gargron](https://github.com/mastodon/mastodon/pull/19426), [Gargron](https://github.com/mastodon/mastodon/pull/19427), [Gargron](https://github.com/mastodon/mastodon/pull/19421), [Gargron](https://github.com/mastodon/mastodon/pull/19417), [Gargron](https://github.com/mastodon/mastodon/pull/19413), [Gargron](https://github.com/mastodon/mastodon/pull/19397), [Gargron](https://github.com/mastodon/mastodon/pull/19387), [Gargron](https://github.com/mastodon/mastodon/pull/19396), [Gargron](https://github.com/mastodon/mastodon/pull/19385), [ykzts](https://github.com/mastodon/mastodon/pull/19334), [ykzts](https://github.com/mastodon/mastodon/pull/19329), [Gargron](https://github.com/mastodon/mastodon/pull/19324), [Gargron](https://github.com/mastodon/mastodon/pull/19318), [Gargron](https://github.com/mastodon/mastodon/pull/19316), [Gargron](https://github.com/mastodon/mastodon/pull/19263), [trwnh](https://github.com/mastodon/mastodon/pull/19305), [ykzts](https://github.com/mastodon/mastodon/pull/19273), [Gargron](https://github.com/mastodon/mastodon/pull/19801), [Gargron](https://github.com/mastodon/mastodon/pull/19790), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19773), [Gargron](https://github.com/mastodon/mastodon/pull/19798), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/19724), [Gargron](https://github.com/mastodon/mastodon/pull/19709), [Gargron](https://github.com/mastodon/mastodon/pull/19514), [Gargron](https://github.com/mastodon/mastodon/pull/19562))
- The web app can now be accessed without being logged in
- No more `/web` prefix on web app paths
- Profiles, posts, and other public pages now use the same interface for logged in and logged out users
@ -77,15 +81,20 @@ Some of the features in this release have been funded through the [NGI0 Discover
- You can peek inside filtered posts anyway
- Change path of privacy policy page from `/terms` to `/privacy-policy` ([Gargron](https://github.com/mastodon/mastodon/pull/19249))
- Change how hashtags are normalized ([Gargron](https://github.com/mastodon/mastodon/pull/18795), [Gargron](https://github.com/mastodon/mastodon/pull/18863), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/18854))
- Change public timelines to be filtered by current locale by default ([Gargron](https://github.com/mastodon/mastodon/pull/19291))
- Change settings area to be separated into categories in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/19407))
- Change public (but not hashtag) timelines to be filtered by current locale by default ([Gargron](https://github.com/mastodon/mastodon/pull/19291), [Gargron](https://github.com/mastodon/mastodon/pull/19563))
- Change settings area to be separated into categories in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/19407), [Gargron](https://github.com/mastodon/mastodon/pull/19533))
- Change "No accounts selected" errors to use the appropriate noun in admin UI ([prplecake](https://github.com/mastodon/mastodon/pull/19356))
- Change e-mail domain blocks to match subdomains of blocked domains ([Gargron](https://github.com/mastodon/mastodon/pull/18979))
- Change custom emoji file size limit from 50 KB to 256 KB ([Gargron](https://github.com/mastodon/mastodon/pull/18788))
- Change "Allow trends without prior review" setting to also work for trending posts ([Gargron](https://github.com/mastodon/mastodon/pull/17977))
- Change admin announcements form to use single inputs for date and time in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18321))
- Change search API to be accessible without being logged in ([Gargron](https://github.com/mastodon/mastodon/pull/18963), [Gargron](https://github.com/mastodon/mastodon/pull/19326))
- Change following and followers API to be accessible without being logged in ([Gargron](https://github.com/mastodon/mastodon/pull/18964))
- Change `AUTHORIZED_FETCH` to not block unauthenticated REST API access ([Gargron](https://github.com/mastodon/mastodon/pull/19803))
- Change Helm configuration ([deepy](https://github.com/mastodon/mastodon/pull/18997), [jgsmith](https://github.com/mastodon/mastodon/pull/18415), [deepy](https://github.com/mastodon/mastodon/pull/18941))
- Change mentions of blocked users to not be processed ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/19725))
- Change max. thumbnail dimensions to 640x360px (360p) ([Gargron](https://github.com/mastodon/mastodon/pull/19619))
- Change post-processing to be deferred only for large media types ([Gargron](https://github.com/mastodon/mastodon/pull/19617))
### Removed
@ -98,6 +107,25 @@ Some of the features in this release have been funded through the [NGI0 Discover
### Fixed
- Fix featured tags not saving preferred casing ([Gargron](https://github.com/mastodon/mastodon/pull/19732))
- Fix language not being saved when editing status ([Gargron](https://github.com/mastodon/mastodon/pull/19543))
- Fix not being able to input featured tag with hash symbol ([Gargron](https://github.com/mastodon/mastodon/pull/19535))
- Fix user clean-up scheduler crash when an unconfirmed account has a moderation note ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/19629))
- Fix being unable to withdraw follow request when confirmation modal is disabled in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/19687))
- Fix inaccurate admin log entry for re-sending confirmation e-mails ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/19674))
- Fix edits not being immediately reflected ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/19673))
- Fix bookmark import stopping at the first failure ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/19669))
- Fix account action type validation ([Gargron](https://github.com/mastodon/mastodon/pull/19476))
- Fix upload progress not communicating processing phase in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/19530))
- Fix wrong host being used for custom.css when asset host configured ([Gargron](https://github.com/mastodon/mastodon/pull/19521))
- Fix account migration form ever using outdated account data ([Gargron](https://github.com/mastodon/mastodon/pull/18429))
- Fix error when uploading malformed CSV import ([Gargron](https://github.com/mastodon/mastodon/pull/19509))
- Fix avatars not using image tags in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/19488))
- Fix handling of duplicate and out-of-order notifications in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/19693))
- Fix reblogs being discarded after the reblogged status ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/19731))
- Fix indexing scheduler trying to index when Elasticsearch is disabled ([Gargron](https://github.com/mastodon/mastodon/pull/19805))
- Fix n+1 queries when rendering initial state JSON ([Gargron](https://github.com/mastodon/mastodon/pull/19795))
- Fix n+1 query during status removal ([Gargron](https://github.com/mastodon/mastodon/pull/19753))
- Fix OCR not working due to Content Security Policy in web UI ([prplecake](https://github.com/mastodon/mastodon/pull/18817))
- Fix `nofollow` rel being removed in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/19455))
- Fix language dropdown causing zoom on mobile devices in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/19428))
@ -248,7 +276,7 @@ Some of the features in this release have been funded through the [NGI0 Discover
### Fixed
- Fix error resposes for `from` search prefix ([single-right-quote](https://github.com/mastodon/mastodon/pull/17963))
- Fix error responses for `from` search prefix ([single-right-quote](https://github.com/mastodon/mastodon/pull/17963))
- Fix dangling language-specific trends ([Gargron](https://github.com/mastodon/mastodon/pull/17997))
- Fix extremely rare race condition when deleting a status or account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17994))
- Fix trends returning less results per page when filtered in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17996))
@ -383,7 +411,7 @@ Some of the features in this release have been funded through the [NGI0 Discover
- Remove profile directory link from main navigation panel in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17688))
- **Remove language detection through cld3** ([Gargron](https://github.com/mastodon/mastodon/pull/17478), [ykzts](https://github.com/mastodon/mastodon/pull/17539), [Gargron](https://github.com/mastodon/mastodon/pull/17496), [Gargron](https://github.com/mastodon/mastodon/pull/17722))
- cld3 is very inaccurate on short-form content even with unique alphabets
- Post language can be overriden individually using `language` param
- Post language can be overridden individually using `language` param
- Otherwise, it defaults to the user's interface language
- Remove support for `OAUTH_REDIRECT_AT_SIGN_IN` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17287))
- Use `OMNIAUTH_ONLY` instead

View file

@ -1,6 +1,6 @@
# Security Policy
If you believe you've identified a security vulnerability in Mastodon (a bug that allows something to happen that shouldn't be possible), you should submit the report through our [Bug Bounty Program][bug-bounty]. Alternatively, you can reach us at <hello@joinmastodon.org>.
If you believe you've identified a security vulnerability in Mastodon (a bug that allows something to happen that shouldn't be possible), you can reach us at <hello@joinmastodon.org>.
You should *not* report such issues on GitHub or in other public spaces to give us time to publish a fix for the issue without exposing Mastodon's users to increased risk.
@ -10,11 +10,8 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 3.5.x | Yes |
| 3.4.x | Yes |
| 3.3.x | No |
| < 3.3 | No |
[bug-bounty]: https://app.intigriti.com/programs/mastodon/mastodonio/detail
| Version | Supported |
| ------- | ----------|
| 4.0.x | Yes |
| 3.5.x | Yes |
| < 3.5 | No |

View file

@ -17,7 +17,7 @@ module Admin
@user.resend_confirmation_instructions
log_action :confirm, @user
log_action :resend, @user
flash[:notice] = I18n.t('admin.accounts.resend_confirmation.success')
redirect_to admin_accounts_path

View file

@ -133,7 +133,7 @@ class Api::BaseController < ApplicationController
end
def disallow_unauthenticated_api_access?
authorized_fetch_mode?
ENV['DISALLOW_UNAUTHENTICATED_API_ACCESS'] == 'true' || Rails.configuration.x.whitelist_mode
end
private

View file

@ -8,7 +8,7 @@ class Api::V1::Accounts::PinsController < Api::BaseController
before_action :set_account
def create
AccountPin.create!(account: current_account, target_account: @account)
AccountPin.find_or_create_by!(account: current_account, target_account: @account)
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships_presenter
end

View file

@ -52,7 +52,7 @@ class Api::V1::FiltersController < Api::BaseController
end
def resource_params
params.permit(:phrase, :expires_in, :irreversible, :whole_word, context: [])
params.permit(:phrase, :expires_in, :irreversible, context: [])
end
def filter_params

View file

@ -7,6 +7,10 @@ class Api::V1::ListsController < Api::BaseController
before_action :require_user!
before_action :set_list, except: [:index, :create]
rescue_from ArgumentError do |e|
render json: { error: e.to_s }, status: 422
end
def index
@lists = List.where(account: current_account).all
render json: @lists, each_serializer: REST::ListSerializer

View file

@ -79,7 +79,7 @@ class Api::V1::StatusesController < Api::BaseController
@status = Status.where(account: current_account).find(params[:id])
authorize @status, :destroy?
@status.discard
@status.discard_with_reblogs
StatusPin.find_by(status: @status)&.destroy
@status.account.statuses_count = @status.account.statuses_count - 1
json = render_to_body json: @status, serializer: REST::StatusSerializer, source_requested: true

View file

@ -24,7 +24,7 @@ class Api::V1::TagsController < Api::BaseController
private
def set_or_create_tag
return not_found unless /\A(#{Tag::HASHTAG_NAME_RE})\z/.match?(params[:id])
return not_found unless Tag::HASHTAG_NAME_RE.match?(params[:id])
@tag = Tag.find_normalized(params[:id]) || Tag.new(name: Tag.normalize(params[:id]), display_name: params[:id])
end
end

View file

@ -35,7 +35,6 @@ class Api::V1::Timelines::PublicController < Api::BaseController
def public_feed
PublicFeed.new(
current_account,
locale: content_locale,
local: truthy_param?(:local),
remote: truthy_param?(:remote),
only_media: truthy_param?(:only_media),

View file

@ -5,7 +5,7 @@ class Api::V1::Trends::TagsController < Api::BaseController
after_action :insert_pagination_headers
DEFAULT_TAGS_LIMIT = 10
DEFAULT_TAGS_LIMIT = (ENV['MAX_TRENDING_TAGS'] || 10).to_i
def index
render json: @tags, each_serializer: REST::TagSerializer, relationships: TagRelationshipsPresenter.new(@tags, current_user&.account_id)

View file

@ -3,7 +3,7 @@
class Api::V2::MediaController < Api::V1::MediaController
def create
@media_attachment = current_account.media_attachments.create!({ delay_processing: true }.merge(media_attachment_params))
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: 202
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: @media_attachment.not_processed? ? 202 : 200
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
render json: file_type_error, status: 422
rescue Paperclip::Error

View file

@ -18,7 +18,8 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
)
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: Devise.omniauth_configs[provider].strategy.display_name.capitalize) if is_navigational_format?
label = Devise.omniauth_configs[provider]&.strategy&.display_name.presence || I18n.t("auth.providers.#{provider}", default: provider.to_s.chomp('_oauth2').capitalize)
set_flash_message(:notice, :success, kind: label) if is_navigational_format?
else
session["devise.#{provider}_data"] = request.env['omniauth.auth']
redirect_to new_user_registration_url

View file

@ -23,7 +23,7 @@ class Settings::FeaturedTagsController < Settings::BaseController
end
def destroy
RemoveFeaturedTagWorker.perform_async(current_account.id, @featured_tag.id)
RemoveFeaturedTagService.new.call(current_account, @featured_tag)
redirect_to settings_featured_tags_path
end

View file

@ -4,15 +4,19 @@ module Admin::ActionLogsHelper
def log_target(log)
case log.target_type
when 'Account'
link_to log.human_identifier, admin_account_path(log.target_id)
link_to (log.human_identifier.presence || I18n.t('admin.action_logs.deleted_account')), admin_account_path(log.target_id)
when 'User'
link_to log.human_identifier, admin_account_path(log.route_param)
if log.route_param.present?
link_to log.human_identifier, admin_account_path(log.route_param)
else
I18n.t('admin.action_logs.deleted_account')
end
when 'UserRole'
link_to log.human_identifier, admin_roles_path(log.target_id)
when 'Report'
link_to "##{log.human_identifier}", admin_report_path(log.target_id)
link_to "##{log.human_identifier.presence || log.target_id}", admin_report_path(log.target_id)
when 'DomainBlock', 'DomainAllow', 'EmailDomainBlock', 'UnavailableDomain'
link_to log.human_identifier, "https://#{log.human_identifier}"
link_to log.human_identifier, "https://#{log.human_identifier.presence}"
when 'Status'
link_to log.human_identifier, log.permalink
when 'AccountWarning'
@ -22,9 +26,13 @@ module Admin::ActionLogsHelper
when 'IpBlock', 'Instance', 'CustomEmoji'
log.human_identifier
when 'CanonicalEmailBlock'
content_tag(:samp, log.human_identifier[0...7], title: log.human_identifier)
content_tag(:samp, (log.human_identifier.presence || '')[0...7], title: log.human_identifier)
when 'Appeal'
link_to log.human_identifier, disputes_strike_path(log.route_param)
if log.route_param.present?
link_to log.human_identifier, disputes_strike_path(log.route_param.presence)
else
I18n.t('admin.action_logs.deleted_account')
end
end
end
end

View file

@ -204,7 +204,7 @@ module ApplicationHelper
permit_visibilities.shift(permit_visibilities.index(default_privacy) + 1) if default_privacy.present?
state_params[:visibility] = params[:visibility] if permit_visibilities.include? params[:visibility]
if user_signed_in?
if user_signed_in? && current_user.functional?
state_params[:settings] = state_params[:settings].merge(Web::Setting.find_by(user: current_user)&.data || {})
state_params[:push_subscription] = current_account.user.web_push_subscription(current_session)
state_params[:current_account] = current_account
@ -212,6 +212,11 @@ module ApplicationHelper
state_params[:admin] = Account.find_local(Setting.site_contact_username.strip.gsub(/\A@/, ''))
end
if user_signed_in? && !current_user.functional?
state_params[:disabled_account] = current_account
state_params[:moved_to_account] = current_account.moved_to_account
end
if single_user_mode?
state_params[:owner] = Account.local.without_suspended.where('id > 0').first
end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true
# rubocop:disable Metrics/ModuleLength, Style/WordArray
module LanguagesHelper
ISO_639_1 = {
@ -189,8 +190,13 @@ module LanguagesHelper
ISO_639_3 = {
ast: ['Asturian', 'Asturianu'].freeze,
ckb: ['Sorani (Kurdish)', 'سۆرانی'].freeze,
jbo: ['Lojban', 'la .lojban.'].freeze,
kab: ['Kabyle', 'Taqbaylit'].freeze,
kmr: ['Kurmanji (Kurdish)', 'Kurmancî'].freeze,
ldn: ['Láadan', 'Láadan'].freeze,
lfn: ['Lingua Franca Nova', 'lingua franca nova'].freeze,
tok: ['Toki Pona', 'toki pona'].freeze,
zba: ['Balaibalan', 'باليبلن'].freeze,
zgh: ['Standard Moroccan Tamazight', 'ⵜⴰⵎⴰⵣⵉⵖⵜ'].freeze,
}.freeze
@ -259,3 +265,5 @@ module LanguagesHelper
locale_name.to_sym if locale_name.present? && I18n.available_locales.include?(locale_name.to_sym)
end
end
# rubocop:enable Metrics/ModuleLength, Style/WordArray

View file

@ -8,7 +8,7 @@ import { recoverHashtags } from 'flavours/glitch/utils/hashtag';
import resizeImage from 'flavours/glitch/utils/resize_image';
import { showAlert, showAlertForError } from './alerts';
import { useEmoji } from './emojis';
import { importFetchedAccounts } from './importer';
import { importFetchedAccounts, importFetchedStatus } from './importer';
import { openModal } from './modal';
import { updateTimeline } from './timelines';
@ -223,6 +223,10 @@ export function submitCompose(routerHistory) {
}
};
if (statusId) {
dispatch(importFetchedStatus({ ...response.data }));
}
if (statusId === null) {
insertIfOnline('home');
}

View file

@ -27,6 +27,7 @@ export default @injectIntl
class Account extends ImmutablePureComponent {
static propTypes = {
size: PropTypes.number,
account: ImmutablePropTypes.map,
onFollow: PropTypes.func.isRequired,
onBlock: PropTypes.func.isRequired,
@ -41,6 +42,10 @@ class Account extends ImmutablePureComponent {
onActionClick: PropTypes.func,
};
static defaultProps = {
size: 36,
};
handleFollow = () => {
this.props.onFollow(this.props.account);
}
@ -75,6 +80,7 @@ class Account extends ImmutablePureComponent {
actionIcon,
actionTitle,
defaultAction,
size,
} = this.props;
if (!account) {
@ -163,7 +169,7 @@ class Account extends ImmutablePureComponent {
<div className='account'>
<div className='account__wrapper'>
<Permalink key={account.get('id')} className='account__display-name' title={account.get('acct')} href={account.get('url')} to={`/@${account.get('acct')}`}>
<div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div>
<div className='account__avatar-wrapper'><Avatar account={account} size={size} /></div>
{mute_expires_at}
<DisplayName account={account} />
</Permalink>

View file

@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedNumber } from 'react-intl';
import ShortNumber from 'mastodon/components/short_number';
import TransitionMotion from 'react-motion/lib/TransitionMotion';
import spring from 'react-motion/lib/spring';
import { reduceMotion } from 'flavours/glitch/initial_state';
@ -51,7 +51,7 @@ export default class AnimatedNumber extends React.PureComponent {
const { direction } = this.state;
if (reduceMotion) {
return obfuscate ? obfuscatedCount(value) : <FormattedNumber value={value} />;
return obfuscate ? obfuscatedCount(value) : <ShortNumber value={value} />;
}
const styles = [{
@ -65,7 +65,7 @@ export default class AnimatedNumber extends React.PureComponent {
{items => (
<span className='animated-number'>
{items.map(({ key, data, style }) => (
<span key={key} style={{ position: (direction * style.y) > 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : <FormattedNumber value={data} />}</span>
<span key={key} style={{ position: (direction * style.y) > 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : <ShortNumber value={data} />}</span>
))}
</span>
)}

View file

@ -63,7 +63,7 @@ class ColumnHeader extends React.PureComponent {
}
handleTitleClick = () => {
this.props.onClick();
this.props.onClick?.();
}
handleMoveLeft = () => {
@ -157,7 +157,6 @@ class ColumnHeader extends React.PureComponent {
className={collapsibleButtonClassName}
title={formatMessage(collapsed ? messages.show : messages.hide)}
aria-label={formatMessage(collapsed ? messages.show : messages.hide)}
aria-pressed={collapsed ? 'false' : 'true'}
onClick={this.handleToggleClick}
>
<i className='icon-with-badge'>

View file

@ -18,7 +18,6 @@ export default class IconButton extends React.PureComponent {
onKeyPress: PropTypes.func,
size: PropTypes.number,
active: PropTypes.bool,
pressed: PropTypes.bool,
expanded: PropTypes.bool,
style: PropTypes.object,
activeStyle: PropTypes.object,
@ -111,7 +110,6 @@ export default class IconButton extends React.PureComponent {
icon,
inverted,
overlay,
pressed,
tabIndex,
title,
counter,
@ -156,7 +154,6 @@ export default class IconButton extends React.PureComponent {
return (
<button
aria-label={title}
aria-pressed={pressed}
aria-expanded={expanded}
title={title}
className={classes}

View file

@ -21,7 +21,12 @@ class NavigationPortal extends React.PureComponent {
render () {
return (
<Switch>
<Route path='/@:acct/(tagged/:tagged?)?' component={AccountNavigation} />
<Route path='/@:acct' exact component={AccountNavigation} />
<Route path='/@:acct/tagged/:tagged?' exact component={AccountNavigation} />
<Route path='/@:acct/with_replies' exact component={AccountNavigation} />
<Route path='/@:acct/followers' exact component={AccountNavigation} />
<Route path='/@:acct/following' exact component={AccountNavigation} />
<Route path='/@:acct/media' exact component={AccountNavigation} />
<Route component={DefaultNavigation} />
</Switch>
);

View file

@ -61,7 +61,7 @@ class ServerBanner extends React.PureComponent {
<div className='server-banner__meta__column'>
<h4><FormattedMessage id='server_banner.administered_by' defaultMessage='Administered by:' /></h4>
<Account id={server.getIn(['contact', 'account', 'id'])} />
<Account id={server.getIn(['contact', 'account', 'id'])} size={36} />
</div>
<div className='server-banner__meta__column'>

View file

@ -42,6 +42,7 @@ const messages = defineMessages({
hide: { id: 'status.hide', defaultMessage: 'Hide toot' },
edited: { id: 'status.edited', defaultMessage: 'Edited {date}' },
filter: { id: 'status.filter', defaultMessage: 'Filter this post' },
openOriginalPage: { id: 'account.open_original_page', defaultMessage: 'Open original page' },
});
export default @injectIntl
@ -182,22 +183,8 @@ class StatusActionBar extends ImmutablePureComponent {
}
handleCopy = () => {
const url = this.props.status.get('url');
const textarea = document.createElement('textarea');
textarea.textContent = url;
textarea.style.position = 'fixed';
document.body.appendChild(textarea);
try {
textarea.select();
document.execCommand('copy');
} catch (e) {
} finally {
document.body.removeChild(textarea);
}
const url = this.props.status.get('url');
navigator.clipboard.writeText(url);
}
handleHideClick = () => {
@ -216,6 +203,7 @@ class StatusActionBar extends ImmutablePureComponent {
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
const pinnableStatus = ['public', 'unlisted', 'private'].includes(status.get('visibility'));
const writtenByMe = status.getIn(['account', 'id']) === me;
const isRemote = status.getIn(['account', 'username']) !== status.getIn(['account', 'acct']);
let menu = [];
let reblogIcon = 'retweet';
@ -225,6 +213,9 @@ class StatusActionBar extends ImmutablePureComponent {
menu.push({ text: intl.formatMessage(messages.open), action: this.handleOpen });
if (publicStatus) {
if (isRemote) {
menu.push({ text: intl.formatMessage(messages.openOriginalPage), href: status.get('url') });
}
menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy });
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
}
@ -315,10 +306,10 @@ class StatusActionBar extends ImmutablePureComponent {
counter={showReplyCount ? status.get('replies_count') : undefined}
obfuscateCount
/>
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} pressed={status.get('reblogged')} title={reblogTitle} icon={reblogIcon} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon={reblogIcon} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
{shareButton}
<IconButton className='status__action-bar-button bookmark-icon' disabled={anonymousAccess} active={status.get('bookmarked')} pressed={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />
<IconButton className='status__action-bar-button bookmark-icon' disabled={anonymousAccess} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />
{filterButton}

View file

@ -332,7 +332,7 @@ export default class StatusContent extends React.PureComponent {
>
<span dangerouslySetInnerHTML={spoilerContent} className='translate' lang={lang} />
{' '}
<button tabIndex='0' className='status__content__spoiler-link' onClick={this.handleSpoilerClick}>
<button type='button' className='status__content__spoiler-link' onClick={this.handleSpoilerClick} aria-expanded={!hidden}>
{toggleText}
</button>
</p>

View file

@ -33,6 +33,7 @@ store.dispatch(fetchCustomEmojis());
const createIdentityContext = state => ({
signedIn: !!state.meta.me,
accountId: state.meta.me,
disabledAccountId: state.meta.disabled_account_id,
accessToken: state.meta.access_token,
permissions: state.role ? state.role.permissions : 0,
});
@ -47,6 +48,7 @@ export default class Mastodon extends React.PureComponent {
identity: PropTypes.shape({
signedIn: PropTypes.bool.isRequired,
accountId: PropTypes.string,
disabledAccountId: PropTypes.string,
accessToken: PropTypes.string,
}).isRequired,
};

View file

@ -1,62 +0,0 @@
import React, { Fragment } from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import PropTypes from 'prop-types';
import configureStore from 'flavours/glitch/store/configureStore';
import { hydrateStore } from 'flavours/glitch/actions/store';
import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from 'mastodon/locales';
import PublicTimeline from 'flavours/glitch/features/standalone/public_timeline';
import HashtagTimeline from 'flavours/glitch/features/standalone/hashtag_timeline';
import ModalContainer from 'flavours/glitch/features/ui/containers/modal_container';
import initialState from 'flavours/glitch/initial_state';
const { localeData, messages } = getLocale();
addLocaleData(localeData);
const store = configureStore();
if (initialState) {
store.dispatch(hydrateStore(initialState));
}
export default class TimelineContainer extends React.PureComponent {
static propTypes = {
locale: PropTypes.string.isRequired,
hashtag: PropTypes.string,
local: PropTypes.bool,
};
static defaultProps = {
local: !initialState.settings.known_fediverse,
};
render () {
const { locale, hashtag, local } = this.props;
let timeline;
if (hashtag) {
timeline = <HashtagTimeline hashtag={hashtag} local={local} />;
} else {
timeline = <PublicTimeline local={local} />;
}
return (
<IntlProvider locale={locale} messages={messages}>
<Provider store={store}>
<Fragment>
{timeline}
{ReactDOM.createPortal(
<ModalContainer />,
document.getElementById('modal-container'),
)}
</Fragment>
</Provider>
</IntlProvider>
);
}
}

View file

@ -125,7 +125,7 @@ class About extends React.PureComponent {
<div className='about__meta__column'>
<h4><FormattedMessage id='server_banner.administered_by' defaultMessage='Administered by:' /></h4>
<Account id={server.getIn(['contact', 'account', 'id'])} />
<Account id={server.getIn(['contact', 'account', 'id'])} size={36} />
</div>
<hr className='about__meta__divider' />
@ -209,6 +209,11 @@ class About extends React.PureComponent {
</Section>
<LinkFooter />
<div className='about__footer'>
<p><FormattedMessage id='about.fork_disclaimer' defaultMessage='Glitch-soc is free open source software forked from Mastodon.' /></p>
<p><FormattedMessage id='about.disclaimer' defaultMessage='Mastodon is free, open-source software, and a trademark of Mastodon gGmbH.' /></p>
</div>
</div>
<Helmet>

View file

@ -53,6 +53,7 @@ const messages = defineMessages({
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
add_account_note: { id: 'account.add_account_note', defaultMessage: 'Add note for @{name}' },
languages: { id: 'account.languages', defaultMessage: 'Change subscribed languages' },
openOriginalPage: { id: 'account.open_original_page', defaultMessage: 'Open original page' },
});
const titleFromAccount = account => {
@ -97,6 +98,7 @@ class Header extends ImmutablePureComponent {
onEditAccountNote: PropTypes.func.isRequired,
onChangeLanguages: PropTypes.func.isRequired,
onInteractionModal: PropTypes.func.isRequired,
onOpenAvatar: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
domain: PropTypes.string.isRequired,
hidden: PropTypes.bool,
@ -132,6 +134,13 @@ class Header extends ImmutablePureComponent {
}
}
handleAvatarClick = e => {
if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
e.preventDefault();
this.props.onOpenAvatar();
}
}
render () {
const { account, hidden, intl, domain } = this.props;
const { signedIn } = this.context.identity;
@ -142,7 +151,9 @@ class Header extends ImmutablePureComponent {
const accountNote = account.getIn(['relationship', 'note']);
const suspended = account.get('suspended');
const suspended = account.get('suspended');
const isRemote = account.get('acct') !== account.get('username');
const remoteDomain = isRemote ? account.get('acct').split('@')[1] : null;
let info = [];
let actionBtn = '';
@ -199,6 +210,11 @@ class Header extends ImmutablePureComponent {
menu.push(null);
}
if (isRemote) {
menu.push({ text: intl.formatMessage(messages.openOriginalPage), href: account.get('url') });
menu.push(null);
}
if ('share' in navigator && !suspended) {
menu.push({ text: intl.formatMessage(messages.share, { name: account.get('username') }), action: this.handleShare });
menu.push(null);
@ -253,15 +269,13 @@ class Header extends ImmutablePureComponent {
menu.push({ text: intl.formatMessage(messages.report, { name: account.get('username') }), action: this.props.onReport });
}
if (signedIn && account.get('acct') !== account.get('username')) {
const domain = account.get('acct').split('@')[1];
if (signedIn && isRemote) {
menu.push(null);
if (account.getIn(['relationship', 'domain_blocking'])) {
menu.push({ text: intl.formatMessage(messages.unblockDomain, { domain }), action: this.props.onUnblockDomain });
menu.push({ text: intl.formatMessage(messages.unblockDomain, { domain: remoteDomain }), action: this.props.onUnblockDomain });
} else {
menu.push({ text: intl.formatMessage(messages.blockDomain, { domain }), action: this.props.onBlockDomain });
menu.push({ text: intl.formatMessage(messages.blockDomain, { domain: remoteDomain }), action: this.props.onBlockDomain });
}
}
@ -299,7 +313,7 @@ class Header extends ImmutablePureComponent {
<div className='account__header__bar'>
<div className='account__header__tabs'>
<a className='avatar' href={account.get('url')} rel='noopener noreferrer' target='_blank'>
<a className='avatar' href={account.get('avatar')} rel='noopener noreferrer' target='_blank' onClick={this.handleAvatarClick}>
<Avatar account={suspended || hidden ? undefined : account} size={90} />
</a>

View file

@ -25,6 +25,7 @@ export default class Header extends ImmutablePureComponent {
onAddToList: PropTypes.func.isRequired,
onChangeLanguages: PropTypes.func.isRequired,
onInteractionModal: PropTypes.func.isRequired,
onOpenAvatar: PropTypes.func.isRequired,
hideTabs: PropTypes.bool,
domain: PropTypes.string.isRequired,
hidden: PropTypes.bool,
@ -102,6 +103,10 @@ export default class Header extends ImmutablePureComponent {
this.props.onInteractionModal(this.props.account);
}
handleOpenAvatar = () => {
this.props.onOpenAvatar(this.props.account);
}
render () {
const { account, hidden, hideTabs } = this.props;
@ -130,6 +135,7 @@ export default class Header extends ImmutablePureComponent {
onEditAccountNote={this.handleEditAccountNote}
onChangeLanguages={this.handleChangeLanguages}
onInteractionModal={this.handleInteractionModal}
onOpenAvatar={this.handleOpenAvatar}
domain={this.props.domain}
hidden={hidden}
/>

View file

@ -4,6 +4,7 @@ import { connect } from 'react-redux';
import { revealAccount } from 'flavours/glitch/actions/accounts';
import { FormattedMessage } from 'react-intl';
import Button from 'flavours/glitch/components/button';
import { domain } from 'flavours/glitch/initial_state';
const mapDispatchToProps = (dispatch, { accountId }) => ({
@ -26,7 +27,7 @@ class LimitedAccountHint extends React.PureComponent {
return (
<div className='limited-account-hint'>
<p><FormattedMessage id='limited_account_hint.title' defaultMessage='This profile has been hidden by the moderators of your server.' /></p>
<p><FormattedMessage id='limited_account_hint.title' defaultMessage='This profile has been hidden by the moderators of {domain}.' values={{ domain }} /></p>
<Button onClick={reveal}><FormattedMessage id='limited_account_hint.action' defaultMessage='Show profile anyway' /></Button>
</div>
);

View file

@ -61,6 +61,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
confirm: intl.formatMessage(messages.cancelFollowRequestConfirm),
onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
}));
} else {
dispatch(unfollowAccount(account.get('id')));
}
} else {
dispatch(followAccount(account.get('id')));
@ -159,6 +161,13 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
}));
},
onOpenAvatar (account) {
dispatch(openModal('IMAGE', {
src: account.get('avatar'),
alt: account.get('acct'),
}));
},
});
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Header));

View file

@ -305,12 +305,12 @@ class ComposeForm extends ImmutablePureComponent {
const countText = this.getFulltextForCharacterCounting();
return (
<div className='composer'>
<div className='compose-form'>
<WarningContainer />
<ReplyIndicatorContainer />
<div className={`composer--spoiler ${spoiler ? 'composer--spoiler--visible' : ''}`} ref={this.setRef}>
<div className={`spoiler-input ${spoiler ? 'spoiler-input--visible' : ''}`} ref={this.setRef}>
<AutosuggestInput
placeholder={intl.formatMessage(messages.spoiler_placeholder)}
value={spoilerText}
@ -352,7 +352,7 @@ class ComposeForm extends ImmutablePureComponent {
</div>
</AutosuggestTextarea>
<div className='composer--options-wrapper'>
<div className='compose-form__buttons-wrapper'>
<OptionsContainer
advancedOptions={advancedOptions}
disabled={isSubmitting}
@ -364,7 +364,7 @@ class ComposeForm extends ImmutablePureComponent {
sensitive={sensitive || (spoilersAlwaysOn && spoilerText && spoilerText.length > 0)}
spoiler={spoilersAlwaysOn ? (spoilerText && spoilerText.length > 0) : spoiler}
/>
<div className='compose--counter-wrapper'>
<div className='character-counter__wrapper'>
<CharacterCounter text={countText} max={maxChars} />
</div>
</div>

View file

@ -16,7 +16,6 @@ import { assignHandlers } from 'flavours/glitch/utils/react_helpers';
export default class ComposerOptionsDropdown extends React.PureComponent {
static propTypes = {
active: PropTypes.bool,
disabled: PropTypes.bool,
icon: PropTypes.string,
items: PropTypes.arrayOf(PropTypes.shape({
@ -162,7 +161,6 @@ export default class ComposerOptionsDropdown extends React.PureComponent {
// Rendering.
render () {
const {
active,
disabled,
title,
icon,
@ -174,35 +172,34 @@ export default class ComposerOptionsDropdown extends React.PureComponent {
closeOnChange,
} = this.props;
const { open, placement } = this.state;
const computedClass = classNames('composer--options--dropdown', {
active,
open,
top: placement === 'top',
});
// The result.
const active = value && items.findIndex(({ name }) => name === value) === (placement === 'bottom' ? 0 : (items.length - 1));
return (
<div
className={computedClass}
className={classNames('privacy-dropdown', placement, { active: open })}
onKeyDown={this.handleKeyDown}
>
<IconButton
active={open || active}
className='value'
disabled={disabled}
icon={icon}
inverted
onClick={this.handleToggle}
onMouseDown={this.handleMouseDown}
onKeyDown={this.handleButtonKeyDown}
onKeyPress={this.handleKeyPress}
size={18}
style={{
height: null,
lineHeight: '27px',
}}
title={title}
/>
<div className={classNames('privacy-dropdown__value', { active })}>
<IconButton
active={open}
className='privacy-dropdown__value-icon'
disabled={disabled}
icon={icon}
inverted
onClick={this.handleToggle}
onMouseDown={this.handleMouseDown}
onKeyDown={this.handleButtonKeyDown}
onKeyPress={this.handleKeyPress}
size={18}
style={{
height: null,
lineHeight: '27px',
}}
title={title}
/>
</div>
<Overlay
containerPadding={20}
placement={placement}

View file

@ -156,7 +156,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent
const active = (name === (this.props.value || this.state.value));
const computedClass = classNames('composer--options--dropdown--content--item', { active });
const computedClass = classNames('privacy-dropdown__option', { active });
let contents = this.props.renderItemContents && this.props.renderItemContents(item, i);
@ -165,7 +165,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent
<React.Fragment>
{icon && <Icon className='icon' fixedWidth id={icon} />}
<div className='content'>
<div className='privacy-dropdown__option__content'>
<strong>{text}</strong>
{meta}
</div>
@ -218,7 +218,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent
// size will be used to determine the coordinate of the menu by
// react-overlays
<div
className='composer--options--dropdown--content'
className='privacy-dropdown__dropdown'
ref={this.handleRef}
role='listbox'
style={{

View file

@ -51,6 +51,15 @@ class LanguageDropdownMenu extends React.PureComponent {
document.addEventListener('click', this.handleDocumentClick, false);
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
this.setState({ mounted: true });
// Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need
// to wait for a frame before focusing
requestAnimationFrame(() => {
if (this.node) {
const element = this.node.querySelector('input[type="search"]');
if (element) element.focus();
}
});
}
componentWillUnmount () {
@ -226,7 +235,7 @@ class LanguageDropdownMenu extends React.PureComponent {
// react-overlays
<div className={`language-dropdown__dropdown ${placement}`} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} ref={this.setRef}>
<div className='emoji-mart-search'>
<input type='search' value={searchValue} onChange={this.handleSearchChange} onKeyDown={this.handleSearchKeyDown} placeholder={intl.formatMessage(messages.search)} autoFocus />
<input type='search' value={searchValue} onChange={this.handleSearchChange} onKeyDown={this.handleSearchKeyDown} placeholder={intl.formatMessage(messages.search)} />
<button className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}>{!isSearching ? loupeIcon : deleteIcon}</button>
</div>

View file

@ -103,7 +103,7 @@ class ToggleOption extends ImmutablePureComponent {
<React.Fragment>
<Toggle checked={checked} onChange={this.handleChange} />
<div className='content'>
<div className='privacy-dropdown__option__content'>
<strong>{text}</strong>
{meta}
</div>
@ -228,7 +228,7 @@ class ComposerOptions extends ImmutablePureComponent {
// The result.
return (
<div className='composer--options'>
<div className='compose-form__buttons'>
<input
accept={acceptContentTypes}
disabled={disabled || !allowMedia}
@ -309,7 +309,6 @@ class ComposerOptions extends ImmutablePureComponent {
)}
<LanguageDropdown />
<Dropdown
active={advancedOptions && advancedOptions.some(value => !!value)}
disabled={disabled || isEditing}
icon='ellipsis-h'
items={advancedOptions ? [

View file

@ -48,7 +48,7 @@ class Publisher extends ImmutablePureComponent {
const { countText, disabled, intl, onSecondarySubmit, privacy, sideArm, isEditing } = this.props;
const diff = maxChars - length(countText || '');
const computedClass = classNames('composer--publisher', {
const computedClass = classNames('compose-form__publish', {
disabled: disabled,
over: diff < 0,
});
@ -72,22 +72,26 @@ class Publisher extends ImmutablePureComponent {
return (
<div className={computedClass}>
{sideArm && !isEditing && sideArm !== 'none' ? (
<Button
className='side_arm'
disabled={disabled}
onClick={onSecondarySubmit}
style={{ padding: null }}
text={<Icon id={privacyIcons[sideArm]} />}
title={`${intl.formatMessage(messages.publish)}: ${intl.formatMessage({ id: `privacy.${sideArm}.short` })}`}
/>
<div className='compose-form__publish-button-wrapper'>
<Button
className='side_arm'
disabled={disabled}
onClick={onSecondarySubmit}
style={{ padding: null }}
text={<Icon id={privacyIcons[sideArm]} />}
title={`${intl.formatMessage(messages.publish)}: ${intl.formatMessage({ id: `privacy.${sideArm}.short` })}`}
/>
</div>
) : null}
<Button
className='primary'
text={publishText}
title={`${intl.formatMessage(messages.publish)}: ${intl.formatMessage({ id: `privacy.${privacy}.short` })}`}
onClick={this.handleSubmit}
disabled={disabled}
/>
<div className='compose-form__publish-button-wrapper'>
<Button
className='primary'
text={publishText}
title={`${intl.formatMessage(messages.publish)}: ${intl.formatMessage({ id: `privacy.${privacy}.short` })}`}
onClick={this.handleSubmit}
disabled={disabled}
/>
</div>
</div>
);
};

View file

@ -49,10 +49,10 @@ class ReplyIndicator extends ImmutablePureComponent {
// The result.
return (
<article className='composer--reply'>
<header>
<article className='reply-indicator'>
<header className='reply-indicator__header'>
<IconButton
className='cancel'
className='reply-indicator__cancel'
icon='times'
onClick={this.handleClick}
title={intl.formatMessage(messages.cancel)}
@ -66,7 +66,7 @@ class ReplyIndicator extends ImmutablePureComponent {
)}
</header>
<div
className='content translate'
className='reply-indicator__content translate'
dangerouslySetInnerHTML={{ __html: content || '' }}
/>
{attachments.size > 0 && (

View file

@ -38,7 +38,7 @@ class TextareaIcons extends ImmutablePureComponent {
render () {
const { advancedOptions, intl } = this.props;
return (
<div className='composer--textarea--icons'>
<div className='compose-form__textarea-icons'>
{advancedOptions ? iconMap.map(
([key, icon, message]) => advancedOptions.get(key) ? (
<span

View file

@ -18,7 +18,7 @@ export default class Upload extends ImmutablePureComponent {
media: ImmutablePropTypes.map.isRequired,
onUndo: PropTypes.func.isRequired,
onOpenFocalPoint: PropTypes.func.isRequired,
isEditingStatus: PropTypes.func.isRequired,
isEditingStatus: PropTypes.bool.isRequired,
};
handleUndoClick = e => {
@ -39,17 +39,17 @@ export default class Upload extends ImmutablePureComponent {
const y = ((focusY / -2) + .5) * 100;
return (
<div className='composer--upload_form--item' tabIndex='0' role='button'>
<div className='compose-form__upload' tabIndex='0' role='button'>
<Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12, }) }}>
{({ scale }) => (
<div style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
<div className='composer--upload_form--actions'>
<div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
<div className='compose-form__upload__actions'>
<button className='icon-button' onClick={this.handleUndoClick}><Icon id='times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button>
{!isEditingStatus && (<button className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>)}
</div>
{(media.get('description') || '').length === 0 && (
<div className='composer--upload_form--item__warning'>
<div className='compose-form__upload__warning'>
<button className='icon-button' onClick={this.handleFocalPointClick}><Icon id='info-circle' /> <FormattedMessage id='upload_form.description_missing' defaultMessage='No description added' /></button>
</div>
)}

View file

@ -14,11 +14,11 @@ export default class UploadForm extends ImmutablePureComponent {
const { mediaIds } = this.props;
return (
<div className='composer--upload_form'>
<div className='compose-form__upload-wrapper'>
<UploadProgressContainer />
{mediaIds.size > 0 && (
<div className='content'>
<div className='compose-form__uploads-wrapper'>
{mediaIds.map(id => (
<UploadContainer id={id} key={id} />
))}

View file

@ -29,17 +29,18 @@ export default class UploadProgress extends React.PureComponent {
}
return (
<div className='composer--upload_form--progress'>
<Icon id='upload' />
<div className='upload-progress'>
<div className='upload-progress__icon'>
<Icon id='upload' />
</div>
<div className='message'>
<div className='upload-progress__message'>
{message}
<div className='backdrop'>
<div className='upload-progress__backdrop'>
<Motion defaultStyle={{ width: 0 }} style={{ width: spring(progress) }}>
{({ width }) =>
(<div className='tracker' style={{ width: `${width}%` }}
/>)
<div className='upload-progress__tracker' style={{ width: `${width}%` }} />
}
</Motion>
</div>

View file

@ -15,7 +15,7 @@ export default class Warning extends React.PureComponent {
return (
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
{({ opacity, scaleX, scaleY }) => (
<div className='composer--warning' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
<div className='compose-form__warning' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
{message}
</div>
)}

View file

@ -25,6 +25,7 @@ const messages = defineMessages({
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
follow: { id: 'account.follow', defaultMessage: 'Follow' },
cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Withdraw follow request' },
cancelFollowRequestConfirm: { id: 'confirmations.cancel_follow_request.confirm', defaultMessage: 'Withdraw request' },
requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' },
unblock: { id: 'account.unblock_short', defaultMessage: 'Unblock' },
unmute: { id: 'account.unmute_short', defaultMessage: 'Unmute' },
@ -45,10 +46,7 @@ const makeMapStateToProps = () => {
const mapDispatchToProps = (dispatch, { intl }) => ({
onFollow(account) {
if (
account.getIn(['relationship', 'following']) ||
account.getIn(['relationship', 'requested'])
) {
if (account.getIn(['relationship', 'following'])) {
if (unfollowModal) {
dispatch(
openModal('CONFIRM', {
@ -66,6 +64,16 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
} else {
dispatch(unfollowAccount(account.get('id')));
}
} else if (account.getIn(['relationship', 'requested'])) {
if (unfollowModal) {
dispatch(openModal('CONFIRM', {
message: <FormattedMessage id='confirmations.cancel_follow_request.message' defaultMessage='Are you sure you want to withdraw your request to follow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
confirm: intl.formatMessage(messages.cancelFollowRequestConfirm),
onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
}));
} else {
dispatch(unfollowAccount(account.get('id')));
}
} else {
dispatch(followAccount(account.get('id')));
}

File diff suppressed because one or more lines are too long

View file

@ -194,7 +194,7 @@ class HashtagTimeline extends React.PureComponent {
const following = tag.get('following');
followButton = (
<button className={classNames('column-header__button')} onClick={this.handleFollow} disabled={!signedIn} title={intl.formatMessage(following ? messages.unfollowHashtag : messages.followHashtag)} aria-label={intl.formatMessage(following ? messages.unfollowHashtag : messages.followHashtag)} aria-pressed={following ? 'true' : 'false'}>
<button className={classNames('column-header__button')} onClick={this.handleFollow} disabled={!signedIn} title={intl.formatMessage(following ? messages.unfollowHashtag : messages.followHashtag)} aria-label={intl.formatMessage(following ? messages.unfollowHashtag : messages.followHashtag)}>
<Icon id={following ? 'user-times' : 'user-plus'} fixedWidth className='column-header__icon' />
</button>
);

View file

@ -131,7 +131,6 @@ class HomeTimeline extends React.PureComponent {
className={classNames('column-header__button', { 'active': showAnnouncements })}
title={intl.formatMessage(showAnnouncements ? messages.hide_announcements : messages.show_announcements)}
aria-label={intl.formatMessage(showAnnouncements ? messages.hide_announcements : messages.show_announcements)}
aria-pressed={showAnnouncements ? 'true' : 'false'}
onClick={this.handleToggleAnnouncementsClick}
>
<IconWithBadge id='bullhorn' count={unreadAnnouncements} />

View file

@ -150,7 +150,7 @@ class InteractionModal extends React.PureComponent {
<div className='interaction-modal__choices__choice'>
<h3><FormattedMessage id='interaction_modal.on_another_server' defaultMessage='On a different server' /></h3>
<p><FormattedMessage id='interaction_modal.other_server_instructions' defaultMessage='Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.' /></p>
<p><FormattedMessage id='interaction_modal.other_server_instructions' defaultMessage='Copy and paste this URL into the search field of your favourite Mastodon app or the web interface of your Mastodon server.' /></p>
<Copypaste value={url} />
</div>
</div>

View file

@ -22,7 +22,7 @@ export default class ColumnSettings extends React.PureComponent {
onRequestNotificationPermission: PropTypes.func,
alertsEnabled: PropTypes.bool,
browserSupport: PropTypes.bool,
browserPermission: PropTypes.bool,
browserPermission: PropTypes.string,
};
onPushChange = (path, checked) => {

View file

@ -64,7 +64,7 @@ const mapStateToProps = state => ({
showFilterBar: state.getIn(['settings', 'notifications', 'quickFilter', 'show']),
notifications: getNotifications(state),
localSettings: state.get('local_settings'),
isLoading: state.getIn(['notifications', 'isLoading'], true),
isLoading: state.getIn(['notifications', 'isLoading'], 0) > 0,
isUnread: state.getIn(['notifications', 'unread']) > 0 || state.getIn(['notifications', 'pendingItems']).size > 0,
hasMore: state.getIn(['notifications', 'hasMore']),
numPending: state.getIn(['notifications', 'pendingItems'], ImmutableList()).size,

View file

@ -207,8 +207,8 @@ class Footer extends ImmutablePureComponent {
return (
<div className='picture-in-picture__footer'>
{replyButton}
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} pressed={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
{withOpenButton && <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.open)} icon='external-link' onClick={this.handleOpenClick} href={status.get('url')} />}
</div>
);

View file

@ -35,6 +35,7 @@ const messages = defineMessages({
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' },
copy: { id: 'status.copy', defaultMessage: 'Copy link to status' },
openOriginalPage: { id: 'account.open_original_page', defaultMessage: 'Open original page' },
});
export default @injectIntl
@ -132,22 +133,8 @@ class ActionBar extends React.PureComponent {
}
handleCopy = () => {
const url = this.props.status.get('url');
const textarea = document.createElement('textarea');
textarea.textContent = url;
textarea.style.position = 'fixed';
document.body.appendChild(textarea);
try {
textarea.select();
document.execCommand('copy');
} catch (e) {
} finally {
document.body.removeChild(textarea);
}
const url = this.props.status.get('url');
navigator.clipboard.writeText(url);
}
render () {
@ -158,10 +145,15 @@ class ActionBar extends React.PureComponent {
const pinnableStatus = ['public', 'unlisted', 'private'].includes(status.get('visibility'));
const mutingConversation = status.get('muted');
const writtenByMe = status.getIn(['account', 'id']) === me;
const isRemote = status.getIn(['account', 'username']) !== status.getIn(['account', 'acct']);
let menu = [];
if (publicStatus) {
if (isRemote) {
menu.push({ text: intl.formatMessage(messages.openOriginalPage), href: status.get('url') });
}
menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy });
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
menu.push(null);

View file

@ -648,7 +648,7 @@ class Status extends ImmutablePureComponent {
showBackButton
multiColumn={multiColumn}
extraButton={(
<button className='column-header__button' title={intl.formatMessage(!isExpanded ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(!isExpanded ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll} aria-pressed={!isExpanded ? 'false' : 'true'}><Icon id={!isExpanded ? 'eye-slash' : 'eye'} /></button>
<button className='column-header__button' title={intl.formatMessage(!isExpanded ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(!isExpanded ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll}><Icon id={!isExpanded ? 'eye-slash' : 'eye'} /></button>
)}
/>

View file

@ -34,7 +34,7 @@ const ColumnLink = ({ icon, text, to, onClick, href, method, badge, transparent,
return (
<a href='#' onClick={onClick && handleOnClick} className={className} title={text} {...other} tabIndex='0'>
{iconElement}
{text}
<span>{text}</span>
{badgeElement}
</a>
);

View file

@ -0,0 +1,92 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import { disabledAccountId, movedToAccountId, domain } from 'flavours/glitch/initial_state';
import { openModal } from 'flavours/glitch/actions/modal';
import { logOut } from 'flavours/glitch/utils/log_out';
const messages = defineMessages({
logoutMessage: { id: 'confirmations.logout.message', defaultMessage: 'Are you sure you want to log out?' },
logoutConfirm: { id: 'confirmations.logout.confirm', defaultMessage: 'Log out' },
});
const mapStateToProps = (state) => ({
disabledAcct: state.getIn(['accounts', disabledAccountId, 'acct']),
movedToAcct: movedToAccountId ? state.getIn(['accounts', movedToAccountId, 'acct']) : undefined,
});
const mapDispatchToProps = (dispatch, { intl }) => ({
onLogout () {
dispatch(openModal('CONFIRM', {
message: intl.formatMessage(messages.logoutMessage),
confirm: intl.formatMessage(messages.logoutConfirm),
closeWhenConfirm: false,
onConfirm: () => logOut(),
}));
},
});
export default @injectIntl
@connect(mapStateToProps, mapDispatchToProps)
class DisabledAccountBanner extends React.PureComponent {
static propTypes = {
disabledAcct: PropTypes.string.isRequired,
movedToAcct: PropTypes.string,
onLogout: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};
handleLogOutClick = e => {
e.preventDefault();
e.stopPropagation();
this.props.onLogout();
return false;
}
render () {
const { disabledAcct, movedToAcct } = this.props;
const disabledAccountLink = (
<Link to={`/@${disabledAcct}`}>
{disabledAcct}@{domain}
</Link>
);
return (
<div className='sign-in-banner'>
<p>
{movedToAcct ? (
<FormattedMessage
id='moved_to_account_banner.text'
defaultMessage='Your account {disabledAccount} is currently disabled because you moved to {movedToAccount}.'
values={{
disabledAccount: disabledAccountLink,
movedToAccount: <Link to={`/@${movedToAcct}`}>{movedToAcct.includes('@') ? movedToAcct : `${movedToAcct}@${domain}`}</Link>,
}}
/>
) : (
<FormattedMessage
id='disabled_account_banner.text'
defaultMessage='Your account {disabledAccount} is currently disabled.'
values={{
disabledAccount: disabledAccountLink,
}}
/>
)}
</p>
<a href='/auth/edit' className='button button--block'>
<FormattedMessage id='disabled_account_banner.account_settings' defaultMessage='Account settings' />
</a>
<button type='button' className='button button--block button-tertiary' onClick={this.handleLogOutClick}>
<FormattedMessage id='confirmations.logout.confirm' defaultMessage='Log out' />
</button>
</div>
);
}
};

View file

@ -58,11 +58,11 @@ class FavouriteModal extends ImmutablePureComponent {
const { status, intl } = this.props;
return (
<div className='modal-root__modal favourite-modal'>
<div className='favourite-modal__container'>
<div className='modal-root__modal boost-modal'>
<div className='boost-modal__container'>
<div className={classNames('status', `status-${status.get('visibility')}`, 'light')}>
<div className='favourite-modal__status-header'>
<div className='favourite-modal__status-time'>
<div className='boost-modal__status-header'>
<div className='boost-modal__status-time'>
<a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
<VisibilityIcon visibility={status.get('visibility')} />
<RelativeTimestamp timestamp={status.get('created_at')} />
@ -90,7 +90,7 @@ class FavouriteModal extends ImmutablePureComponent {
</div>
</div>
<div className='favourite-modal__action-bar'>
<div className='boost-modal__action-bar'>
<div><FormattedMessage id='favourite_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='star' /></span> }} /></div>
<Button text={intl.formatMessage(messages.favourite)} onClick={this.handleFavourite} ref={this.setRef} />
</div>

View file

@ -0,0 +1,59 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { defineMessages, injectIntl } from 'react-intl';
import IconButton from 'flavours/glitch/components/icon_button';
import ImageLoader from './image_loader';
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
});
export default @injectIntl
class ImageModal extends React.PureComponent {
static propTypes = {
src: PropTypes.string.isRequired,
alt: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};
state = {
navigationHidden: false,
};
toggleNavigation = () => {
this.setState(prevState => ({
navigationHidden: !prevState.navigationHidden,
}));
};
render () {
const { intl, src, alt, onClose } = this.props;
const { navigationHidden } = this.state;
const navigationClassName = classNames('media-modal__navigation', {
'media-modal__navigation--hidden': navigationHidden,
});
return (
<div className='modal-root__modal media-modal'>
<div className='media-modal__closer' role='presentation' onClick={onClose} >
<ImageLoader
src={src}
width={400}
height={400}
alt={alt}
onClick={this.toggleNavigation}
/>
</div>
<div className={navigationClassName}>
<IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={40} />
</div>
</div>
);
}
}

View file

@ -3,7 +3,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import { version, repository, source_url, profile_directory as profileDirectory } from 'flavours/glitch/initial_state';
import { domain, version, source_url, profile_directory as profileDirectory } from 'flavours/glitch/initial_state';
import { logOut } from 'flavours/glitch/utils/log_out';
import { openModal } from 'flavours/glitch/actions/modal';
import { PERMISSION_INVITE_USERS } from 'flavours/glitch/permissions';
@ -48,45 +48,44 @@ class LinkFooter extends React.PureComponent {
render () {
const { signedIn, permissions } = this.context.identity;
const items = [];
items.push(<a key='apps' href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Get the app' /></a>);
items.push(<Link key='about' to='/about'><FormattedMessage id='navigation_bar.info' defaultMessage='About' /></Link>);
items.push(<a key='mastodon' href='https://joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.what_is_mastodon' defaultMessage='About Mastodon' /></a>);
items.push(<a key='docs' href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a>);
items.push(<Link key='privacy-policy' to='/privacy-policy'><FormattedMessage id='getting_started.privacy_policy' defaultMessage='Privacy Policy' /></Link>);
items.push(<Link key='hotkeys' to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link>);
if (profileDirectory) {
items.push(<Link key='directory' to='/directory'><FormattedMessage id='getting_started.directory' defaultMessage='Directory' /></Link>);
}
if (signedIn) {
if ((permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS) {
items.push(<a key='invites' href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a>);
}
items.push(<a key='security' href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a>);
items.push(<a key='logout' href='/auth/sign_out' onClick={this.handleLogoutClick}><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a>);
}
const canInvite = signedIn && ((permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS);
const canProfileDirectory = profileDirectory;
return (
<div className='getting-started__footer'>
<ul>
{items.map((item, index, array) => (
<li>{item} { index === array.length - 1 ? null : ' · ' }</li>
))}
</ul>
<div className='link-footer'>
<p>
<strong>{domain}</strong>:
{' '}
<Link key='about' to='/about'><FormattedMessage id='footer.about' defaultMessage='About' /></Link>
{canInvite && (
<>
{' · '}
<a key='invites' href='/invites' target='_blank'><FormattedMessage id='footer.invite' defaultMessage='Invite people' /></a>
</>
)}
{canProfileDirectory && (
<>
{' · '}
<Link key='directory' to='/directory'><FormattedMessage id='footer.directory' defaultMessage='Profiles directory' /></Link>
</>
)}
{' · '}
<Link key='privacy-policy' to='/privacy-policy'><FormattedMessage id='footer.privacy_policy' defaultMessage='Privacy policy' /></Link>
</p>
<p>
<FormattedMessage
id='getting_started.open_source_notice.queer_af'
defaultMessage='queer.af is open source software, running on a fork of {Glitchsoc} and {Mastodon}. You can contribute or report issues at {github}.'
values={{
github: <span><a href={source_url} rel='noopener noreferrer' target='_blank'>{repository}</a> (v{version})</span>,
Glitchsoc: <span><a href='https://github.com/glitch-soc/mastodon' rel='noopener noreferrer' target='_blank'>glitch-soc</a></span>,
Mastodon: <a href='https://github.com/tootsuite/mastodon' rel='noopener noreferrer' target='_blank'>mastodon</a> }}
/>
<strong>Mastodon, queer.af edition</strong>:
{' '}
<a href='https://joinmastodon.org' target='_blank'><FormattedMessage id='footer.about' defaultMessage='About' /></a>
{' · '}
<a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='footer.get_app' defaultMessage='Get the app' /></a>
{' · '}
<Link to='/keyboard-shortcuts'><FormattedMessage id='footer.keyboard_shortcuts' defaultMessage='Keyboard shortcuts' /></Link>
{' · '}
<a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='footer.source_code' defaultMessage='View source code' /></a>
{' · '}
v{version}
</p>
</div>
);

View file

@ -15,6 +15,7 @@ import DoodleModal from './doodle_modal';
import ConfirmationModal from './confirmation_modal';
import FocalPointModal from './focal_point_modal';
import DeprecatedSettingsModal from './deprecated_settings_modal';
import ImageModal from './image_modal';
import {
OnboardingModal,
MuteModal,
@ -38,6 +39,7 @@ const MODAL_COMPONENTS = {
'ONBOARDING': OnboardingModal,
'VIDEO': () => Promise.resolve({ default: VideoModal }),
'AUDIO': () => Promise.resolve({ default: AudioModal }),
'IMAGE': () => Promise.resolve({ default: ImageModal }),
'BOOST': () => Promise.resolve({ default: BoostModal }),
'FAVOURITE': () => Promise.resolve({ default: FavouriteModal }),
'DOODLE': () => Promise.resolve({ default: DoodleModal }),

View file

@ -4,6 +4,7 @@ import { defineMessages, injectIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import { timelinePreview, showTrends } from 'flavours/glitch/initial_state';
import ColumnLink from 'flavours/glitch/features/ui/components/column_link';
import DisabledAccountBanner from './disabled_account_banner';
import FollowRequestsColumnLink from './follow_requests_column_link';
import ListPanel from './list_panel';
import NotificationsCounterIcon from './notifications_counter_icon';
@ -42,7 +43,7 @@ class NavigationPanel extends React.Component {
render() {
const { intl, onOpenSettings } = this.props;
const { signedIn } = this.context.identity;
const { signedIn, disabledAccountId } = this.context.identity;
return (
<div className='navigation-panel'>
@ -70,7 +71,7 @@ class NavigationPanel extends React.Component {
{!signedIn && (
<div className='navigation-panel__sign-in-banner'>
<hr />
<SignInBanner />
{ disabledAccountId ? <DisabledAccountBanner /> : <SignInBanner /> }
</div>
)}

View file

@ -54,6 +54,7 @@
* @property {boolean} crop_images
* @property {boolean=} delete_modal
* @property {boolean=} disable_swiping
* @property {string=} disabled_account_id
* @property {boolean} display_media
* @property {string} domain
* @property {boolean=} expand_spoilers
@ -61,6 +62,7 @@
* @property {string} locale
* @property {string | null} mascot
* @property {string=} me
* @property {string=} moved_to_account_id
* @property {string=} owner
* @property {boolean} profile_directory
* @property {boolean} registrations_open
@ -111,6 +113,7 @@ export const boostModal = getMeta('boost_modal');
export const cropImages = getMeta('crop_images');
export const deleteModal = getMeta('delete_modal');
export const disableSwiping = getMeta('disable_swiping');
export const disabledAccountId = getMeta('disabled_account_id');
export const displayMedia = getMeta('display_media');
export const domain = getMeta('domain');
export const expandSpoilers = getMeta('expand_spoilers');
@ -118,6 +121,7 @@ export const forceSingleColumn = !getMeta('advanced_layout');
export const limitedFederationMode = getMeta('limited_federation_mode');
export const mascot = getMeta('mascot');
export const me = getMeta('me');
export const movedToAccountId = getMeta('moved_to_account_id');
export const owner = getMeta('owner');
export const profile_directory = getMeta('profile_directory');
export const reduceMotion = getMeta('reduce_motion');

View file

@ -21,3 +21,12 @@ es:
skins:
glitch:
default: Predeterminado
ja:
flavours:
glitch:
description: GlitchSocインスタンスのデフォルトフレーバーです。
name: Glitch Edition
skins:
glitch:
default: デフォルト

View file

@ -573,6 +573,7 @@ export default function compose(state = initialState, action) {
'advanced_options',
map => map.merge(new ImmutableMap({ do_not_federate }))
);
map.set('id', null);
if (action.status.get('spoiler_text').length > 0) {
map.set('spoiler', true);

View file

@ -52,20 +52,26 @@ const initialState = ImmutableMap({
markNewForDelete: false,
});
const notificationToMap = (state, notification) => ImmutableMap({
const notificationToMap = (notification, markForDelete) => ImmutableMap({
id: notification.id,
type: notification.type,
account: notification.account.id,
markedForDelete: state.get('markNewForDelete'),
markedForDelete: markForDelete,
status: notification.status ? notification.status.id : null,
report: notification.report ? fromJS(notification.report) : null,
});
const normalizeNotification = (state, notification, usePendingItems) => {
const markNewForDelete = state.get('markNewForDelete');
const top = state.get('top');
// Under currently unknown conditions, the client may receive duplicates from the server
if (state.get('pendingItems').some((item) => item?.get('id') === notification.id) || state.get('items').some((item) => item?.get('id') === notification.id)) {
return state;
}
if (usePendingItems || !state.get('pendingItems').isEmpty()) {
return state.update('pendingItems', list => list.unshift(notificationToMap(state, notification))).update('unread', unread => unread + 1);
return state.update('pendingItems', list => list.unshift(notificationToMap(notification, markNewForDelete))).update('unread', unread => unread + 1);
}
if (shouldCountUnreadNotifications(state)) {
@ -79,32 +85,79 @@ const normalizeNotification = (state, notification, usePendingItems) => {
list = list.take(20);
}
return list.unshift(notificationToMap(state, notification));
return list.unshift(notificationToMap(notification, markNewForDelete));
});
};
const expandNormalizedNotifications = (state, notifications, next, isLoadingRecent, usePendingItems) => {
const lastReadId = state.get('lastReadId');
let items = ImmutableList();
const expandNormalizedNotifications = (state, notifications, next, isLoadingMore, isLoadingRecent, usePendingItems) => {
// This method is pretty tricky because:
// - existing notifications might be out of order
// - the existing notifications may have gaps, most often explicitly noted with a `null` item
// - ideally, we don't want it to reorder existing items
// - `notifications` may include items that are already included
// - this function can be called either to fill in a gap, or load newer items
notifications.forEach((n, i) => {
items = items.set(i, notificationToMap(state, n));
});
const markNewForDelete = state.get('markNewForDelete');
const lastReadId = state.get('lastReadId');
const newItems = ImmutableList(notifications.map((notification) => notificationToMap(notification, markNewForDelete)));
return state.withMutations(mutable => {
if (!items.isEmpty()) {
if (!newItems.isEmpty()) {
usePendingItems = isLoadingRecent && (usePendingItems || !mutable.get('pendingItems').isEmpty());
mutable.update(usePendingItems ? 'pendingItems' : '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')),
);
mutable.update(usePendingItems ? 'pendingItems' : 'items', oldItems => {
// If called to poll *new* notifications, we just need to add them on top without duplicates
if (isLoadingRecent) {
const idsToCheck = oldItems.map(item => item?.get('id')).toSet();
const insertedItems = newItems.filterNot(item => idsToCheck.includes(item.get('id')));
return insertedItems.concat(oldItems);
}
const firstIndex = 1 + list.take(lastIndex).findLastIndex(
item => item !== null && compareId(item.get('id'), items.first().get('id')) > 0,
);
// If called to expand more (presumably older than any known to the WebUI), we just have to
// add them to the bottom without duplicates
if (isLoadingMore) {
const idsToCheck = oldItems.map(item => item?.get('id')).toSet();
const insertedItems = newItems.filterNot(item => idsToCheck.includes(item.get('id')));
return oldItems.concat(insertedItems);
}
return list.take(firstIndex).concat(items, list.skip(lastIndex));
// Now this gets tricky, as we don't necessarily know for sure where the gap to fill is,
// and some items in the timeline may not be properly ordered.
// However, we know that `newItems.last()` is the oldest item that was requested and that
// there is no “hole” between `newItems.last()` and `newItems.first()`.
// First, find the furthest (if properly sorted, oldest) item in the notifications that is
// newer than the oldest fetched one, as it's most likely that it delimits the gap.
// Start the gap *after* that item.
const lastIndex = oldItems.findLastIndex(item => item !== null && compareId(item.get('id'), newItems.last().get('id')) >= 0) + 1;
// Then, try to find the furthest (if properly sorted, oldest) item in the notifications that
// is newer than the most recent fetched one, as it delimits a section comprised of only
// items older or within `newItems` (or that were deleted from the server, so should be removed
// anyway).
// Stop the gap *after* that item.
const firstIndex = oldItems.take(lastIndex).findLastIndex(item => item !== null && compareId(item.get('id'), newItems.first().get('id')) > 0) + 1;
// At this point:
// - no `oldItems` after `firstIndex` is newer than any of the `newItems`
// - all `oldItems` after `lastIndex` are older than every of the `newItems`
// - it is possible for items in the replaced slice to be older than every `newItems`
// - it is possible for items before `firstIndex` to be in the `newItems` range
// Therefore:
// - to avoid losing items, items from the replaced slice that are older than `newItems`
// should be added in the back.
// - to avoid duplicates, `newItems` should be checked the first `firstIndex` items of
// `oldItems`
const idsToCheck = oldItems.take(firstIndex).map(item => item?.get('id')).toSet();
const insertedItems = newItems.filterNot(item => idsToCheck.includes(item.get('id')));
const olderItems = oldItems.slice(firstIndex, lastIndex).filter(item => item !== null && compareId(item.get('id'), newItems.last().get('id')) < 0);
return oldItems.take(firstIndex).concat(
insertedItems,
olderItems,
oldItems.skip(lastIndex),
);
});
}
@ -115,7 +168,7 @@ const expandNormalizedNotifications = (state, notifications, next, isLoadingRece
if (shouldCountUnreadNotifications(state)) {
mutable.set('unread', mutable.get('pendingItems').count(item => item !== null) + mutable.get('items').count(item => item && compareId(item.get('id'), lastReadId) > 0));
} else {
const mostRecent = items.find(item => item !== null);
const mostRecent = newItems.find(item => item !== null);
if (mostRecent && compareId(lastReadId, mostRecent.get('id')) < 0) {
mutable.set('lastReadId', mostRecent.get('id'));
}
@ -264,7 +317,7 @@ export default function notifications(state = initialState, action) {
case NOTIFICATIONS_UPDATE:
return normalizeNotification(state, action.notification, action.usePendingItems);
case NOTIFICATIONS_EXPAND_SUCCESS:
return expandNormalizedNotifications(state, action.notifications, action.next, action.isLoadingRecent, action.usePendingItems);
return expandNormalizedNotifications(state, action.notifications, action.next, action.isLoadingMore, action.isLoadingRecent, action.usePendingItems);
case ACCOUNT_BLOCK_SUCCESS:
return filterNotifications(state, [action.relationship.id]);
case ACCOUNT_MUTE_SUCCESS:

View file

@ -29,22 +29,22 @@ $emojis-requiring-inversion: 'back' 'copyright' 'curly_loop' 'currency_exchange'
.hicolor-privacy-icons {
.status__visibility-icon.fa-globe,
.composer--options--dropdown--content--item .fa-globe {
.privacy-dropdown__option .fa-globe {
color: #1976d2;
}
.status__visibility-icon.fa-unlock,
.composer--options--dropdown--content--item .fa-unlock {
.privacy-dropdown__option .fa-unlock {
color: #388e3c;
}
.status__visibility-icon.fa-lock,
.composer--options--dropdown--content--item .fa-lock {
.privacy-dropdown__option .fa-lock {
color: #ffa000;
}
.status__visibility-icon.fa-envelope,
.composer--options--dropdown--content--item .fa-envelope {
.privacy-dropdown__option .fa-envelope {
color: #d32f2f;
}
}

View file

@ -204,7 +204,8 @@
}
.account-role,
.simple_form .recommended {
.simple_form .recommended,
.simple_form .not_recommended {
display: inline-block;
padding: 4px 6px;
cursor: default;
@ -229,6 +230,12 @@
}
}
.simple_form .not_recommended {
color: lighten($error-red, 12%);
background-color: rgba(lighten($error-red, 12%), 0.1);
border-color: rgba(lighten($error-red, 12%), 0.5);
}
.account__header__fields {
max-width: 100vw;
padding: 0;

View file

@ -30,6 +30,34 @@
}
}
.link-footer {
flex: 0 0 auto;
padding: 10px;
padding-top: 20px;
z-index: 1;
font-size: 13px;
p {
color: $dark-text-color;
margin-bottom: 20px;
strong {
font-weight: 500;
}
a {
color: $dark-text-color;
text-decoration: underline;
&:hover,
&:focus,
&:active {
text-decoration: none;
}
}
}
}
.about {
padding: 20px;
@ -37,6 +65,14 @@
border-radius: 4px;
}
&__footer {
color: $dark-text-color;
text-align: center;
font-size: 15px;
line-height: 22px;
margin-top: 20px;
}
&__header {
margin-bottom: 30px;
@ -157,7 +193,7 @@
}
}
.getting-started__footer {
.link-footer {
padding: 0;
margin-top: 60px;
text-align: center;

View file

@ -1,4 +1,4 @@
.composer {
.compose-form {
padding: 10px;
.emoji-picker-dropdown {
@ -25,16 +25,16 @@
}
}
.no-reduce-motion .composer--spoiler {
.no-reduce-motion .spoiler-input {
transition: height 0.4s ease, opacity 0.4s ease;
}
.composer--spoiler {
.spoiler-input {
height: 0;
transform-origin: bottom;
opacity: 0.0;
&.composer--spoiler--visible {
&.spoiler-input--visible {
height: 36px;
margin-bottom: 11px;
opacity: 1.0;
@ -64,7 +64,7 @@
}
}
.composer--warning {
.compose-form__warning {
color: $inverted-text-color;
margin-bottom: 15px;
background: $ui-primary-color;
@ -123,7 +123,7 @@
}
}
.composer--reply {
.reply-indicator {
margin: 0 0 10px;
border-radius: 4px;
padding: 10px;
@ -131,117 +131,117 @@
min-height: 23px;
overflow-y: auto;
flex: 0 2 auto;
}
& > header {
margin-bottom: 5px;
overflow: hidden;
.reply-indicator__header {
margin-bottom: 5px;
overflow: hidden;
& > .account.small { color: $inverted-text-color; }
& > .account.small { color: $inverted-text-color; }
}
& > .cancel {
float: right;
line-height: 24px;
.reply-indicator__cancel {
float: right;
line-height: 24px;
}
.reply-indicator__content {
position: relative;
margin: 10px 0;
padding: 0 12px;
font-size: 14px;
line-height: 20px;
color: $inverted-text-color;
word-wrap: break-word;
font-weight: 400;
overflow: visible;
white-space: pre-wrap;
padding-top: 5px;
overflow: hidden;
p, pre, blockquote {
margin-bottom: 20px;
white-space: pre-wrap;
&:last-child {
margin-bottom: 0;
}
}
& > .content {
position: relative;
margin: 10px 0;
padding: 0 12px;
font-size: 14px;
line-height: 20px;
h1, h2, h3, h4, h5 {
margin-top: 20px;
margin-bottom: 20px;
}
h1, h2 {
font-weight: 700;
font-size: 18px;
}
h2 {
font-size: 16px;
}
h3, h4, h5 {
font-weight: 500;
}
blockquote {
padding-left: 10px;
border-left: 3px solid $inverted-text-color;
color: $inverted-text-color;
word-wrap: break-word;
font-weight: 400;
overflow: visible;
white-space: pre-wrap;
padding-top: 5px;
overflow: hidden;
white-space: normal;
p, pre, blockquote {
margin-bottom: 20px;
white-space: pre-wrap;
&:last-child {
margin-bottom: 0;
}
p:last-child {
margin-bottom: 0;
}
}
h1, h2, h3, h4, h5 {
margin-top: 20px;
margin-bottom: 20px;
b, strong {
font-weight: 700;
}
em, i {
font-style: italic;
}
sub {
font-size: smaller;
vertical-align: sub;
}
sup {
font-size: smaller;
vertical-align: super;
}
ul, ol {
margin-left: 1em;
p {
margin: 0;
}
}
h1, h2 {
font-weight: 700;
font-size: 18px;
}
ul {
list-style-type: disc;
}
h2 {
font-size: 16px;
}
ol {
list-style-type: decimal;
}
h3, h4, h5 {
font-weight: 500;
}
a {
color: $lighter-text-color;
text-decoration: none;
blockquote {
padding-left: 10px;
border-left: 3px solid $inverted-text-color;
color: $inverted-text-color;
white-space: normal;
&:hover { text-decoration: underline }
p:last-child {
margin-bottom: 0;
}
}
&.mention {
&:hover {
text-decoration: none;
b, strong {
font-weight: 700;
}
em, i {
font-style: italic;
}
sub {
font-size: smaller;
vertical-align: sub;
}
sup {
font-size: smaller;
vertical-align: super;
}
ul, ol {
margin-left: 1em;
p {
margin: 0;
}
}
ul {
list-style-type: disc;
}
ol {
list-style-type: decimal;
}
a {
color: $lighter-text-color;
text-decoration: none;
&:hover { text-decoration: underline }
&.mention {
&:hover {
text-decoration: none;
span { text-decoration: underline }
}
span { text-decoration: underline }
}
}
}
@ -253,8 +253,12 @@
}
}
.compose-form__autosuggest-wrapper,
.autosuggest-input {
.compose-form .compose-form__autosuggest-wrapper {
position: relative;
}
.compose-form .autosuggest-textarea,
.compose-form .autosuggest-input {
position: relative;
width: 100%;
@ -284,10 +288,6 @@
all: unset;
}
&:disabled {
background: $ui-secondary-color;
}
&:focus {
outline: 0;
}
@ -304,7 +304,7 @@
}
}
.composer--textarea--icons {
.compose-form__textarea-icons {
display: block;
position: absolute;
top: 29px;
@ -401,25 +401,25 @@
}
}
.composer--upload_form {
.compose-form__upload-wrapper {
overflow: hidden;
& > .content {
display: flex;
flex-direction: row;
flex-wrap: wrap;
font-family: inherit;
padding: 5px;
overflow: hidden;
}
}
.composer--upload_form--item {
.compose-form__uploads-wrapper {
display: flex;
flex-direction: row;
flex-wrap: wrap;
font-family: inherit;
padding: 5px;
overflow: hidden;
}
.compose-form__upload {
flex: 1 1 0;
margin: 5px;
min-width: 40%;
& > div {
.compose-form__upload-thumbnail {
position: relative;
border-radius: 4px;
height: 140px;
@ -459,54 +459,54 @@
}
}
.composer--upload_form--actions {
.compose-form__upload__actions {
background: linear-gradient(180deg, rgba($base-shadow-color, 0.8) 0, rgba($base-shadow-color, 0.35) 80%, transparent);
display: flex;
align-items: flex-start;
justify-content: space-between;
}
.composer--upload_form--progress {
.upload-progress {
display: flex;
padding: 10px;
color: $darker-text-color;
overflow: hidden;
& > .fa {
.fa {
font-size: 34px;
margin-right: 10px;
}
& > .message {
flex: 1 1 auto;
& > span {
display: block;
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
}
& > .backdrop {
position: relative;
margin-top: 5px;
border-radius: 6px;
width: 100%;
height: 6px;
background: $ui-base-lighter-color;
& > .tracker {
position: absolute;
top: 0;
left: 0;
height: 6px;
border-radius: 6px;
background: $ui-highlight-color;
}
}
span {
display: block;
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
}
}
.upload-progress__message {
flex: 1 1 auto;
}
.upload-progress__backdrop {
position: relative;
margin-top: 5px;
border-radius: 6px;
width: 100%;
height: 6px;
background: $ui-base-lighter-color;
}
.upload-progress__tracker {
position: absolute;
top: 0;
left: 0;
height: 6px;
border-radius: 6px;
background: $ui-highlight-color;
}
.compose-form__modifiers {
color: $inverted-text-color;
font-family: inherit;
@ -514,7 +514,7 @@
background: $simple-background-color;
}
.composer--options-wrapper {
.compose-form__buttons-wrapper {
padding: 10px;
background: darken($simple-background-color, 8%);
border-radius: 0 0 4px 4px;
@ -524,7 +524,7 @@
flex: 0 0 auto;
}
.composer--options {
.compose-form__buttons {
display: flex;
flex: 0 0 auto;
@ -551,30 +551,41 @@
}
}
.compose--counter-wrapper {
.character-counter__wrapper {
align-self: center;
margin-right: 4px;
}
.composer--options--dropdown {
&.open {
& > .value {
border-radius: 4px 4px 0 0;
box-shadow: 0 -4px 4px rgba($base-shadow-color, 0.1);
color: $primary-text-color;
background: $ui-highlight-color;
.privacy-dropdown.active {
.privacy-dropdown__value {
background: $simple-background-color;
border-radius: 4px 4px 0 0;
box-shadow: 0 -4px 4px rgba($base-shadow-color, 0.1);
.icon-button {
transition: none;
}
&.top {
& > .value {
border-radius: 0 0 4px 4px;
box-shadow: 0 4px 4px rgba($base-shadow-color, 0.1);
&.active {
background: $ui-highlight-color;
.icon-button {
color: $primary-text-color;
}
}
}
&.top .privacy-dropdown__value {
border-radius: 0 0 4px 4px;
}
.privacy-dropdown__dropdown {
display: block;
box-shadow: 2px 4px 6px rgba($base-shadow-color, 0.1);
}
}
.composer--options--dropdown--content {
.privacy-dropdown__dropdown {
position: absolute;
border-radius: 4px;
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
@ -583,14 +594,14 @@
transform-origin: 50% 0;
}
.composer--options--dropdown--content--item {
.privacy-dropdown__option {
display: flex;
align-items: center;
padding: 10px;
color: $inverted-text-color;
cursor: pointer;
& > .content {
.privacy-dropdown__option__content {
flex: 1 1 auto;
color: $lighter-text-color;
@ -608,7 +619,7 @@
background: $ui-highlight-color;
color: $primary-text-color;
& > .content {
.privacy-dropdown__option__content {
color: $primary-text-color;
strong { color: $primary-text-color }
@ -618,31 +629,25 @@
&.active:hover { background: lighten($ui-highlight-color, 4%) }
}
.composer--publisher {
padding-top: 10px;
text-align: right;
white-space: nowrap;
overflow: hidden;
.compose-form__publish {
display: flex;
justify-content: flex-end;
min-width: 0;
flex: 0 0 auto;
column-gap: 5px;
& > .primary {
display: inline-block;
margin: 0;
padding: 7px 10px;
text-align: center;
}
.compose-form__publish-button-wrapper {
overflow: hidden;
padding-top: 10px;
& > .side_arm {
display: inline-block;
margin: 0 5px;
padding: 7px 0;
width: 36px;
text-align: center;
}
button {
padding: 7px 10px;
text-align: center;
}
&.over {
& > .count { color: $warning-red }
& > .side_arm {
width: 36px;
}
}
}

View file

@ -132,6 +132,10 @@
&:active {
outline: 0 !important;
}
&::-webkit-search-cancel-button {
display: none;
}
}
}

View file

@ -1044,43 +1044,6 @@
color: $dark-text-color;
}
&__footer {
flex: 0 0 auto;
padding: 10px;
padding-top: 20px;
z-index: 1;
font-size: 13px;
ul {
margin-bottom: 10px;
}
ul li {
display: inline;
}
p {
color: $dark-text-color;
margin-bottom: 20px;
a {
color: $dark-text-color;
text-decoration: underline;
}
}
a {
text-decoration: none;
color: $darker-text-color;
&:hover,
&:focus,
&:active {
text-decoration: underline;
}
}
}
&__trends {
flex: 0 1 auto;
opacity: 1;
@ -1775,7 +1738,7 @@ noscript {
@import 'domains';
@import 'status';
@import 'modal';
@import 'composer';
@import 'compose_form';
@import 'columns';
@import 'regeneration_indicator';
@import 'directory';

View file

@ -416,7 +416,6 @@
}
.boost-modal,
.favourite-modal,
.confirmation-modal,
.report-modal,
.actions-modal,
@ -461,7 +460,7 @@
}
}
.favourite-modal .status-direct {
.boost-modal .status-direct {
background-color: inherit;
}
@ -478,8 +477,7 @@
}
}
.boost-modal__container,
.favourite-modal__container {
.boost-modal__container {
overflow-x: scroll;
padding: 10px;
@ -490,7 +488,6 @@
}
.boost-modal__action-bar,
.favourite-modal__action-bar,
.confirmation-modal__action-bar,
.mute-modal__action-bar,
.block-modal__action-bar {
@ -512,13 +509,11 @@
}
}
.boost-modal__status-header,
.favourite-modal__status-header {
.boost-modal__status-header {
font-size: 15px;
}
.boost-modal__status-time,
.favourite-modal__status-time {
.boost-modal__status-time {
float: right;
font-size: 14px;
}
@ -1290,11 +1285,11 @@
}
}
.modal-root__container .composer--options--dropdown {
.modal-root__container .privacy-dropdown {
flex-grow: 0;
}
.modal-root__container .composer--options--dropdown--content {
.modal-root__container .privacy-dropdown__dropdown {
pointer-events: auto;
z-index: 9999;
}

View file

@ -4,6 +4,20 @@
p {
color: $darker-text-color;
margin-bottom: 20px;
a {
color: $secondary-text-color;
text-decoration: none;
unicode-bidi: isolate;
&:hover {
text-decoration: underline;
.fa {
color: lighten($dark-text-color, 7%);
}
}
}
}
.button {

View file

@ -41,7 +41,7 @@
flex: 0 1 48px;
}
.composer {
.compose-form {
flex: 1;
overflow-y: hidden;
display: flex;
@ -59,10 +59,6 @@
.autosuggest-textarea__textarea {
overflow-y: hidden;
}
.compose-form__upload-thumbnail {
height: 80px;
}
}
.navigation-panel {

View file

@ -659,6 +659,7 @@
display: inline-block;
font-weight: 500;
font-size: 12px;
line-height: 17px;
margin-left: 6px;
}

View file

@ -37,7 +37,7 @@
}
.compose-standalone {
.composer {
.compose-form {
width: 400px;
margin: 0 auto;
padding: 20px 0;

View file

@ -1,36 +1,20 @@
// components.scss
.status__content a,
.reply-indicator__content a {
color: lighten($ui-highlight-color, 12%);
text-decoration: underline;
&.mention {
text-decoration: none;
}
&.mention span {
text-decoration: underline;
&:hover,
&:focus,
&:active {
text-decoration: none;
.compose-form {
.compose-form__modifiers {
.compose-form__upload {
&-description {
input {
&::placeholder {
opacity: 1;
}
}
}
}
}
&:hover,
&:focus,
&:active {
text-decoration: none;
}
&.status__content__spoiler-link {
color: $secondary-text-color;
text-decoration: none;
}
}
.status__content a,
.link-footer a,
.reply-indicator__content a,
.status__content__read-more-button {
text-decoration: underline;
@ -39,31 +23,56 @@
&:active {
text-decoration: none;
}
&.mention {
text-decoration: none;
span {
text-decoration: underline;
}
&:hover,
&:focus,
&:active {
span {
text-decoration: none;
}
}
}
}
.getting-started__footer a {
text-decoration: underline;
&:hover,
&:focus,
&:active {
text-decoration: none;
}
.status__content a {
color: $highlight-text-color;
}
.nothing-here {
color: $darker-text-color;
}
.public-layout .public-account-header__tabs__tabs .counter.active::after {
border-bottom: 4px solid $ui-highlight-color;
.compose-form__poll-wrapper .button.button-secondary,
.compose-form .autosuggest-textarea__textarea::placeholder,
.compose-form .spoiler-input__input::placeholder,
.report-dialog-modal__textarea::placeholder,
.language-dropdown__dropdown__results__item__common-name,
.compose-form .icon-button {
color: $inverted-text-color;
}
.composer {
.composer--spoiler input,
.compose-form__autosuggest-wrapper textarea {
&::placeholder {
color: $inverted-text-color;
}
.text-icon-button.active {
color: $ui-highlight-color;
}
.language-dropdown__dropdown__results__item.active {
background: $ui-highlight-color;
font-weight: 500;
}
.link-button:disabled {
cursor: not-allowed;
&:hover,
&:focus,
&:active {
text-decoration: none !important;
}
}

View file

@ -14,8 +14,8 @@ $ui-highlight-color: $classic-highlight-color !default;
$darker-text-color: lighten($ui-primary-color, 20%) !default;
$dark-text-color: lighten($ui-primary-color, 12%) !default;
$secondary-text-color: lighten($ui-secondary-color, 6%) !default;
$highlight-text-color: lighten($ui-highlight-color, 8%) !default;
$action-button-color: #8d9ac2;
$highlight-text-color: lighten($ui-highlight-color, 10%) !default;
$action-button-color: lighten($ui-base-color, 50%);
$inverted-text-color: $black !default;
$lighter-text-color: darken($ui-base-color,6%) !default;

View file

@ -103,7 +103,8 @@ code {
}
}
.recommended {
.recommended,
.not_recommended {
position: absolute;
margin: 0 4px;
margin-top: -2px;

View file

@ -1,200 +1,250 @@
// Notes!
// Sass color functions, "darken" and "lighten" are automatically replaced.
.glitch.local-settings {
background: $ui-base-color;
html {
scrollbar-color: $ui-base-color rgba($ui-base-color, 0.25);
}
&__navigation {
background: darken($ui-base-color, 8%);
// Change the colors of button texts
.button {
color: $white;
&.button-alternative-2 {
color: $white;
}
}
.status-card__actions button,
.status-card__actions a {
color: rgba($white, 0.8);
&:hover,
&:active,
&:focus {
color: $white;
}
}
// Change default background colors of columns
.column > .scrollable,
.getting-started,
.column-inline-form,
.error-column,
.regeneration-indicator {
background: $white;
border: 1px solid lighten($ui-base-color, 8%);
border-top: 0;
}
.column > .scrollable.about {
border-top: 1px solid lighten($ui-base-color, 8%);
}
.about__meta,
.about__section__title,
.interaction-modal {
background: $white;
border: 1px solid lighten($ui-base-color, 8%);
}
.rules-list li::before {
background: $ui-highlight-color;
}
.directory__card__img {
background: lighten($ui-base-color, 12%);
}
.filter-form {
background: $white;
border-bottom: 1px solid lighten($ui-base-color, 8%);
}
.column-back-button,
.column-header {
background: $white;
border: 1px solid lighten($ui-base-color, 8%);
@media screen and (max-width: $no-gap-breakpoint) {
border-top: 0;
}
&__navigation__item {
background: darken($ui-base-color, 8%);
&--slim-button {
top: -50px;
right: 0;
}
}
&:hover {
.column-header__back-button,
.column-header__button,
.column-header__button.active,
.account__header {
background: $white;
}
.column-header__button.active {
color: $ui-highlight-color;
&:hover,
&:active,
&:focus {
color: $ui-highlight-color;
background: $white;
}
}
.account__header__bar .avatar .account__avatar {
border-color: $white;
}
.getting-started__footer a {
color: $ui-secondary-color;
text-decoration: underline;
}
.confirmation-modal__secondary-button,
.confirmation-modal__cancel-button,
.mute-modal__cancel-button,
.block-modal__cancel-button {
color: lighten($ui-base-color, 26%);
&:hover,
&:focus,
&:active {
color: $primary-text-color;
}
}
.column-subheading {
background: darken($ui-base-color, 4%);
border-bottom: 1px solid lighten($ui-base-color, 8%);
}
.getting-started,
.scrollable {
.column-link {
background: $white;
border-bottom: 1px solid lighten($ui-base-color, 8%);
&:hover,
&:active,
&:focus {
background: $ui-base-color;
}
}
}
.notification__dismiss-overlay {
.wrappy {
box-shadow: unset;
}
.getting-started .navigation-bar {
border-top: 1px solid lighten($ui-base-color, 8%);
border-bottom: 1px solid lighten($ui-base-color, 8%);
.ckbox {
text-shadow: unset;
@media screen and (max-width: $no-gap-breakpoint) {
border-top: 0;
}
}
.status.status-direct {
background: darken($ui-base-color, 8%);
border-bottom-color: darken($ui-base-color, 12%);
.compose-form__autosuggest-wrapper,
.poll__option input[type="text"],
.compose-form .spoiler-input__input,
.compose-form__poll-wrapper select,
.search__input,
.setting-text,
.report-dialog-modal__textarea,
.audio-player {
border: 1px solid lighten($ui-base-color, 8%);
}
&.collapsed> .status__content:after {
background: linear-gradient(rgba(darken($ui-base-color, 8%), 0), rgba(darken($ui-base-color, 8%), 1));
.report-dialog-modal .dialog-option .poll__input {
color: $white;
}
.search__input {
@media screen and (max-width: $no-gap-breakpoint) {
border-top: 0;
border-bottom: 0;
}
}
.focusable:focus.status.status-direct {
background: darken($ui-base-color, 4%);
&.collapsed> .status__content:after {
background: linear-gradient(rgba(darken($ui-base-color, 4%), 0), rgba(darken($ui-base-color, 4%), 1));
}
.list-editor .search .search__input {
border-top: 0;
border-bottom: 0;
}
// Change columns' default background colors
.column {
> .scrollable {
background: darken($ui-base-color, 13%);
}
.compose-form__poll-wrapper select {
background: $simple-background-color url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 8%))}'/></svg>") no-repeat right 8px center / auto 16px;
}
.status.collapsed .status__content:after {
background: linear-gradient(rgba(darken($ui-base-color, 13%), 0), rgba(darken($ui-base-color, 13%), 1));
.compose-form__poll-wrapper,
.compose-form__poll-wrapper .poll__footer {
border-top-color: lighten($ui-base-color, 8%);
}
.drawer__inner {
.notification__filter-bar {
border: 1px solid lighten($ui-base-color, 8%);
border-top: 0;
}
.compose-form .compose-form__buttons-wrapper {
background: $ui-base-color;
border: 1px solid lighten($ui-base-color, 8%);
border-top: 0;
}
.drawer__header,
.drawer__inner {
background: $white;
border: 1px solid lighten($ui-base-color, 8%);
}
.drawer__inner__mastodon {
background: $ui-base-color url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color(darken($ui-base-color, 13%))}"/></svg>') no-repeat bottom / 100% auto !important;
.mastodon {
filter: contrast(75%) brightness(75%) !important;
}
background: $white url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-color)}"/></svg>') no-repeat bottom / 100% auto;
}
// Change the default appearance of the content warning button
.status__content {
// Change the colors used in compose-form
.compose-form {
.compose-form__modifiers {
.compose-form__upload__actions .icon-button {
color: lighten($white, 7%);
.status__content__spoiler-link {
background: lighten($ui-base-color, 30%);
&:hover {
background: lighten($ui-base-color, 35%);
text-decoration: none;
&:active,
&:focus,
&:hover {
color: $white;
}
}
}
.compose-form__upload-description input {
color: lighten($white, 7%);
}
// Change the background colors of media and video spoilers
.media-spoiler,
.video-player__spoiler,
.account-gallery__item a {
background: $ui-base-color;
}
// Change the colors used in the dropdown menu
.dropdown-menu {
background: $ui-base-color;
}
.dropdown-menu__arrow {
&.left {
border-left-color: $ui-base-color;
}
&.top {
border-top-color: $ui-base-color;
}
&.bottom {
border-bottom-color: $ui-base-color;
}
&.right {
border-right-color: $ui-base-color;
}
}
.dropdown-menu__item {
a,
button {
background: $ui-base-color;
color: $ui-secondary-color;
}
}
// Change the default color of several parts of the compose form
.composer {
.composer--spoiler input, .compose-form__autosuggest-wrapper textarea {
color: lighten($ui-base-color, 80%);
&:disabled { background: lighten($simple-background-color, 10%) }
&::placeholder {
color: lighten($ui-base-color, 70%);
&::placeholder {
color: lighten($white, 7%);
}
}
}
.composer--options-wrapper {
background: lighten($ui-base-color, 10%);
.compose-form__buttons-wrapper {
background: darken($ui-base-color, 6%);
}
.composer--options > hr {
display: none;
.autosuggest-textarea__suggestions {
background: darken($ui-base-color, 6%);
}
.composer--options--dropdown--content--item {
color: $ui-primary-color;
strong {
color: $ui-primary-color;
.autosuggest-textarea__suggestions__item {
&:hover,
&:focus,
&:active,
&.selected {
background: lighten($ui-base-color, 4%);
}
}
}
.composer--upload_form--actions .icon-button {
color: lighten($white, 7%);
&:active,
&:focus,
&:hover {
color: $white;
}
}
.language-dropdown__dropdown__results__item:hover,
.language-dropdown__dropdown__results__item:focus,
.language-dropdown__dropdown__results__item:active {
background-color: $ui-base-color;
}
.dropdown-menu__separator,
.dropdown-menu__item.edited-timestamp__history__item,
.dropdown-menu__container__header,
.compare-history-modal .report-modal__target,
.report-dialog-modal .poll__option.dialog-option {
border-bottom-color: lighten($ui-base-color, 12%);
}
.report-dialog-modal__container {
border-bottom-color: lighten($ui-base-color, 12%);
}
.status__content,
.reply-indicator__content {
a {
color: $highlight-text-color;
}
}
.emoji-mart-bar {
border-color: darken($ui-base-color, 4%);
border-color: lighten($ui-base-color, 4%);
&:first-child {
background: lighten($ui-base-color, 10%);
background: darken($ui-base-color, 6%);
}
}
@ -203,35 +253,121 @@
border-color: $ui-base-color;
}
.autosuggest-textarea__suggestions {
background: lighten($ui-base-color, 10%)
// Change the background colors of statuses
.focusable:focus {
background: $ui-base-color;
}
.autosuggest-textarea__suggestions__item {
.detailed-status,
.detailed-status__action-bar {
background: $white;
}
// Change the background colors of status__content__spoiler-link
.reply-indicator__content .status__content__spoiler-link,
.status__content .status__content__spoiler-link {
background: $ui-base-color;
&:hover,
&:focus,
&:active,
&.selected {
background: darken($ui-base-color, 4%);
&:focus {
background: lighten($ui-base-color, 4%);
}
}
.react-toggle-track {
background: $ui-secondary-color;
// Change the background colors of media and video spoilers
.media-spoiler,
.video-player__spoiler {
background: $ui-base-color;
}
.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track {
background: lighten($ui-secondary-color, 10%);
.privacy-dropdown.active .privacy-dropdown__value.active .icon-button {
color: $white;
}
.react-toggle.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track {
background: darken($ui-highlight-color, 10%);
.account-gallery__item a {
background-color: $ui-base-color;
}
// Change the colors used in the dropdown menu
.dropdown-menu {
background: $white;
&__arrow {
&.left {
border-left-color: $white;
}
&.top {
border-top-color: $white;
}
&.bottom {
border-bottom-color: $white;
}
&.right {
border-right-color: $white;
}
}
&__item {
a,
button {
background: $white;
color: $darker-text-color;
}
}
}
// Change the text colors on inverted background
.privacy-dropdown__option.active,
.privacy-dropdown__option:hover,
.privacy-dropdown__option.active .privacy-dropdown__option__content,
.privacy-dropdown__option.active .privacy-dropdown__option__content strong,
.privacy-dropdown__option:hover .privacy-dropdown__option__content,
.privacy-dropdown__option:hover .privacy-dropdown__option__content strong,
.dropdown-menu__item a:active,
.dropdown-menu__item a:focus,
.dropdown-menu__item a:hover,
.actions-modal ul li:not(:empty) a.active,
.actions-modal ul li:not(:empty) a.active button,
.actions-modal ul li:not(:empty) a:active,
.actions-modal ul li:not(:empty) a:active button,
.actions-modal ul li:not(:empty) a:focus,
.actions-modal ul li:not(:empty) a:focus button,
.actions-modal ul li:not(:empty) a:hover,
.actions-modal ul li:not(:empty) a:hover button,
.language-dropdown__dropdown__results__item.active,
.admin-wrapper .sidebar ul .simple-navigation-active-leaf a,
.simple_form .block-button,
.simple_form .button,
.simple_form button {
color: $white;
}
.language-dropdown__dropdown__results__item .language-dropdown__dropdown__results__item__common-name {
color: lighten($ui-base-color, 8%);
}
.language-dropdown__dropdown__results__item.active .language-dropdown__dropdown__results__item__common-name {
color: darken($ui-base-color, 12%);
}
.dropdown-menu__separator,
.dropdown-menu__item.edited-timestamp__history__item,
.dropdown-menu__container__header,
.compare-history-modal .report-modal__target,
.report-dialog-modal .poll__option.dialog-option {
border-bottom-color: lighten($ui-base-color, 4%);
}
.report-dialog-modal__container {
border-top-color: lighten($ui-base-color, 4%);
}
// Change the background colors of modals
.actions-modal,
.boost-modal,
.favourite-modal,
.confirmation-modal,
.mute-modal,
.block-modal,
@ -243,12 +379,43 @@
.compare-history-modal,
.report-modal__comment .setting-text__wrapper,
.report-modal__comment .setting-text,
.report-dialog-modal__textarea {
.announcements,
.picture-in-picture__header,
.picture-in-picture__footer,
.reactions-bar__item {
background: $white;
border: 1px solid lighten($ui-base-color, 8%);
}
.report-dialog-modal .dialog-option .poll__input {
.reactions-bar__item:hover,
.reactions-bar__item:focus,
.reactions-bar__item:active,
.language-dropdown__dropdown__results__item:hover,
.language-dropdown__dropdown__results__item:focus,
.language-dropdown__dropdown__results__item:active {
background-color: $ui-base-color;
}
.reactions-bar__item.active {
background-color: mix($white, $ui-highlight-color, 80%);
border-color: mix(lighten($ui-base-color, 8%), $ui-highlight-color, 80%);
}
.media-modal__overlay .picture-in-picture__footer {
border: 0;
}
.picture-in-picture__header {
border-bottom: 0;
}
.announcements,
.picture-in-picture__footer {
border-top: 0;
}
.icon-with-badge__badge {
border-color: $white;
color: $white;
}
@ -260,8 +427,43 @@
border-top-color: lighten($ui-base-color, 8%);
}
.column-header__collapsible-inner {
background: darken($ui-base-color, 4%);
border: 1px solid lighten($ui-base-color, 8%);
border-top: 0;
}
.dashboard__quick-access,
.focal-point__preview strong,
.admin-wrapper .content__heading__tabs a.selected {
color: $white;
}
.button.button-tertiary {
&:hover,
&:focus,
&:active {
color: $white;
}
}
.button.button-secondary {
border-color: $darker-text-color;
color: $darker-text-color;
&:hover,
&:focus,
&:active {
border-color: darken($darker-text-color, 8%);
color: darken($darker-text-color, 8%);
}
}
.flash-message.warning {
color: lighten($gold-star, 16%);
}
.boost-modal__action-bar,
.favourite-modal__action-bar,
.confirmation-modal__action-bar,
.mute-modal__action-bar,
.block-modal__action-bar,
@ -279,33 +481,134 @@
}
}
.display-case__case {
background: $white;
}
.embed-modal .embed-modal__container .embed-modal__html {
background: $white;
border: 1px solid lighten($ui-base-color, 8%);
&:focus {
border-color: lighten($ui-base-color, 12%);
background: $white;
}
}
.react-toggle-track {
background: $ui-secondary-color;
}
.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track {
background: darken($ui-secondary-color, 10%);
}
.react-toggle.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track {
background: lighten($ui-highlight-color, 10%);
}
// Change the default color used for the text in an empty column or on the error column
.empty-column-indicator,
.error-column {
color: lighten($ui-base-color, 60%);
color: $primary-text-color;
background: $white;
}
// Change the default colors used on some parts of the profile pages
.activity-stream-tabs {
background: $account-background-color;
border-bottom-color: lighten($ui-base-color, 8%);
}
a {
&.active {
color: $ui-primary-color;
}
.nothing-here,
.page-header,
.directory__tag > a,
.directory__tag > div {
background: $white;
border: 1px solid lighten($ui-base-color, 8%);
@media screen and (max-width: $no-gap-breakpoint) {
border-left: 0;
border-right: 0;
border-top: 0;
}
}
.simple_form {
input[type="text"],
input[type="number"],
input[type="email"],
input[type="password"],
textarea {
&:hover {
border-color: lighten($ui-base-color, 12%);
}
}
}
.picture-in-picture-placeholder {
background: $white;
border-color: lighten($ui-base-color, 8%);
color: lighten($ui-base-color, 8%);
}
.directory__tag > a {
&:hover,
&:active,
&:focus {
background: $ui-base-color;
}
@media screen and (max-width: $no-gap-breakpoint) {
border: 0;
}
}
.directory__tag.active > a,
.directory__tag.active > div {
border-color: $ui-highlight-color;
&,
h4,
h4 small,
.fa,
.trends__item__current {
color: $white;
}
&:hover,
&:active,
&:focus {
background: $ui-highlight-color;
}
}
.batch-table {
&__toolbar,
&__row,
.nothing-here {
border-color: lighten($ui-base-color, 8%);
}
}
.activity-stream {
border: 1px solid lighten($ui-base-color, 8%);
&--under-tabs {
border-top: 0;
}
.entry {
background: $account-background-color;
.detailed-status.light,
.more.light,
.status.light {
border-bottom-color: lighten($ui-base-color, 8%);
}
}
.status.light {
.status__content {
color: $primary-text-color;
}
@ -315,17 +618,14 @@
color: $primary-text-color;
}
}
}
}
.accounts-grid {
.account-grid-card {
.controls {
.icon-button {
color: $ui-secondary-color;
color: $darker-text-color;
}
}
@ -336,13 +636,53 @@
}
.username {
color: $ui-secondary-color;
color: $darker-text-color;
}
.account__header__content {
color: $primary-text-color;
}
}
}
.simple_form {
.warning {
box-shadow: none;
background: rgba($error-red, 0.5);
text-shadow: none;
}
.recommended {
border-color: $ui-highlight-color;
color: $ui-highlight-color;
background-color: rgba($ui-highlight-color, 0.1);
}
}
.compose-form .compose-form__warning {
border-color: $ui-highlight-color;
background-color: rgba($ui-highlight-color, 0.1);
&,
a {
color: $ui-highlight-color;
}
}
.reply-indicator {
background: transparent;
border: 1px solid lighten($ui-base-color, 8%);
}
.dismissable-banner {
border-left: 1px solid lighten($ui-base-color, 8%);
border-right: 1px solid lighten($ui-base-color, 8%);
}
.status__content,
.reply-indicator__content {
a {
color: $highlight-text-color;
}
}
@ -354,6 +694,7 @@
}
}
.notification__filter-bar button.active::after,
.account__section-headline a.active::after {
border-color: transparent transparent $white;
}
@ -364,7 +705,10 @@
.activity-stream,
.nothing-here,
.directory__tag > a,
.directory__tag > div {
.directory__tag > div,
.card > a,
.page-header,
.compose-form .compose-form__warning {
box-shadow: none;
}
@ -372,3 +716,55 @@
border: 1px solid lighten($ui-base-color, 8%);
background: $simple-background-color url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 8%))}'/></svg>") no-repeat right 8px center / auto 16px;
}
// Glitch-soc-specific changes
.glitch.local-settings {
background: $ui-base-color;
border: 1px solid lighten($ui-base-color, 8%);
}
.glitch.local-settings__navigation {
background: darken($ui-base-color, 8%);
}
.glitch.local-settings__navigation__item {
background: darken($ui-base-color, 8%);
border-bottom: 1px lighten($ui-base-color, 8%) solid;
&:hover {
background: $ui-base-color;
}
&.active {
background: $ui-highlight-color;
color: $white;
}
&.close, &.close:hover {
background: $error-value-color;
color: $primary-text-color;
}
}
.notification__dismiss-overlay {
.wrappy {
box-shadow: unset;
.ckbox {
text-shadow: unset;
}
}
}
.status.collapsed .status__content:after {
background: linear-gradient(rgba(darken($ui-base-color, 13%), 0), rgba(darken($ui-base-color, 13%), 1));
}
.drawer__inner__mastodon {
background: $white url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-color)}"/></svg>') no-repeat bottom / 100% auto !important;
.mastodon {
filter: contrast(75%) brightness(75%) !important;
}
}

View file

@ -7,11 +7,17 @@ $classic-primary-color: #9baec8;
$classic-secondary-color: #d9e1e8;
$classic-highlight-color: #6364ff;
// Differences
$success-green: lighten(#3c754d, 8%);
$base-overlay-background: $white !default;
$valid-value-color: $success-green !default;
$ui-base-color: $classic-secondary-color !default;
$ui-base-lighter-color: darken($ui-base-color, 57%);
$ui-highlight-color: $classic-highlight-color !default;
$ui-primary-color: $classic-primary-color !default;
$ui-base-lighter-color: #b0c0cf;
$ui-primary-color: #9bcbed;
$ui-secondary-color: $classic-base-color !default;
$ui-highlight-color: $classic-highlight-color !default;
$primary-text-color: $black !default;
$darker-text-color: $classic-base-color !default;
@ -19,17 +25,14 @@ $highlight-text-color: darken($ui-highlight-color, 8%) !default;
$dark-text-color: #444b5d;
$action-button-color: #606984;
$success-green: lighten(#3c754d, 8%);
$base-overlay-background: $white !default;
$inverted-text-color: $black !default;
$lighter-text-color: $classic-base-color !default;
$light-text-color: #444b5d;
// Newly added colors
$account-background-color: $white !default;
//Invert darkened and lightened colors
// Invert darkened and lightened colors
@function darken($color, $amount) {
@return hsl(hue($color), saturation($color), lightness($color) + $amount);
}

View file

@ -36,17 +36,12 @@ body.rtl {
margin-left: 5px;
}
.composer .compose--counter-wrapper {
.compose-form .character-counter__wrapper {
margin-right: 0;
margin-left: 4px;
}
.composer--publisher {
text-align: left;
}
.boost-modal__status-time,
.favourite-modal__status-time {
.boost-modal__status-time {
float: left;
}

View file

@ -22,3 +22,12 @@ es:
skins:
vanilla:
default: Predeterminado
ja:
flavours:
vanilla:
description: バニラのMastodonインスタンスで使われるテーマです。このテーマはGlitchSocのすべての機能をサポートしない可能性があります。
name: Vanilla Mastodon
skins:
vanilla:
default: デフォルト

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 950 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

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