Compare commits

..

70 Commits

Author SHA1 Message Date
Tarrien
deb56f0c8a Update to current 4.3.0-alpha-glitch-soc, update theming files 2024-02-16 10:14:20 -05:00
Tarrien
fff7926498 Rebase to current 4.3.0-alpha-glitch-soc, update theming files 2024-02-16 10:14:20 -05:00
root
aeb49bcba0 Modern theme update to latest version 2024-02-16 10:14:20 -05:00
root
04ec9163d1 Modern theme update 2024-02-16 10:14:20 -05:00
root
d44ca8e5c2 fix Modern theme when split into separtate flavour 2024-02-16 10:14:20 -05:00
root
fb4a6f3382 Migrate Modern theme to separate Flavour 2024-02-16 10:14:20 -05:00
root
24e6f14ac8 Migrate Modern theme to separate Flavour 2024-02-16 10:14:20 -05:00
root
8f958d6ac7 Re-add Modern theme, with color variants 2024-02-16 10:14:20 -05:00
root
3c00c65a19 dev work 2024-02-16 10:14:20 -05:00
tarrien
1a722f5dd0 Delete .env.production.old 2024-02-16 10:14:20 -05:00
tarrien
73eee37115 Cleanup 2024-02-16 10:14:20 -05:00
Tarrien
93add68b0d Block gpt via robots.txt 2024-02-16 10:14:20 -05:00
Tarrien
e87a7669df Final save before migration 2024-02-16 10:14:20 -05:00
Tarrien
9cbd80d29b Fixing some customization tweaks 2024-02-16 10:14:20 -05:00
Tarrien
1b65423543 Wobbl customizations on Glitch-SOC 2024-02-16 10:14:20 -05:00
Tarrien
b207eecefa Theming and such 2024-02-16 10:14:20 -05:00
Tarrien
c754efef32 Update to 4.1.3 2024-02-16 10:14:20 -05:00
Claire
160fca7661 Bump version to v4.1.3 2024-02-16 10:14:20 -05:00
Renaud Chaput
523708fdad Allow carets in URL search params (#25216) 2024-02-16 10:14:20 -05:00
Vyr Cossont
c10078f719 Fix Redis client and type errors introduced in #24285 (#24342) 2024-02-16 10:14:20 -05:00
Vyr Cossont
ce4a9873db IndexingScheduler: fetch and import in batches (#24285)
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
2024-02-16 10:14:20 -05:00
Claire
ed60d9ce51 Change /api/v1/statuses/:id/history to always return at least one item (#25510) 2024-02-16 10:14:20 -05:00
Daniel M Brasil
4396ad28ef Fix incorrect pagination headers in /api/v2/admin/accounts (#25477) 2024-02-16 10:14:20 -05:00
Claire
24cfaab748 Fix infinite loop in AccountsStatusesCleanupScheduler (#24840) 2024-02-16 10:14:20 -05:00
Claire
ac128c0a50 Improve automatic post cleanup worker performances (#24785) 2024-02-16 10:14:20 -05:00
Claire
553d862ae4 Fix AccountsStatusesCleanupScheduler not spreading deletes across accounts correctly (#24607) 2024-02-16 10:14:20 -05:00
Claire
3d910d7cf0 Change automatic post deletion thresholds and load detection (#24614) 2024-02-16 10:14:20 -05:00
Claire
be9c9396b0 Fix ArgumentError when loading newer Private Mentions (#25399) 2024-02-16 10:14:20 -05:00
Claire
bcb66beb6a Bump version to v4.1.2 2024-02-16 10:14:20 -05:00
Claire
3a252178ca Bump version to v4.1.1 2024-02-16 10:14:20 -05:00
Claire
53c5096f66 Add mail headers to avoid auto-replies (#23597) 2024-02-16 10:14:19 -05:00
Claire
d7d477047e Bump version to v4.3.0-alpha.3 (#29241) 2024-02-16 12:17:15 +01:00
Claire
6c1b6194f7 Merge pull request from GHSA-jhrq-qvrm-qr36
* Fix insufficient Content-Type checking of fetched ActivityStreams objects

* Allow JSON-LD documents with multiple profiles
2024-02-16 12:17:15 +01:00
renovate[bot]
63080e10a9 Update dependency pg to v1.5.5 (#29230)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-16 10:06:25 +01:00
Claire
e7ca82762d Fix user creation failure handling in OAuth paths (#29207) 2024-02-14 23:12:59 +01:00
Claire
486e4bc7d3 Fix OmniAuth tests (#29201) 2024-02-14 16:07:28 +01:00
Claire
40439399c6 Bump version to v4.3.0-alpha.2 (#29200) 2024-02-14 15:26:18 +01:00
Claire
53b73ed6a2 Merge pull request from GHSA-vm39-j3vx-pch3
* Prevent different identities from a same SSO provider from accessing a same account

* Lock auth provider changes behind `ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH=true`

* Rename methods to avoid confusion between OAuth and OmniAuth
2024-02-14 15:25:15 +01:00
Emelia Smith
436419cc2f Merge pull request from GHSA-7w3c-p9j8-mq3x
* Ensure destruction of OAuth Applications notifies streaming

Due to doorkeeper using a dependent: delete_all relationship, the destroy of an OAuth Application bypassed the existing AccessTokenExtension callbacks for announcing destructing of access tokens.

* Ensure password resets revoke access to Streaming API

* Improve performance of deleting OAuth tokens

---------

Co-authored-by: Claire <claire.github-309c@sitedethib.com>
2024-02-14 15:25:15 +01:00
Claire
3c3ef8b9d3 Add sidekiq_unique_jobs:delete_all_locks task and disable sidekiq-unique-jobs UI by default (#29199) 2024-02-14 13:42:15 +01:00
Emelia Smith
eae436c5a8 Disable administrative doorkeeper routes (#29187) 2024-02-13 20:03:00 +01:00
Emelia Smith
b83076647e Ignore legacy moderator and admin columns on User model (#29188) 2024-02-13 20:03:00 +01:00
renovate[bot]
7100106f3f Update dependency sidekiq-unique-jobs to v7.1.33 (#29175)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-13 20:03:00 +01:00
renovate[bot]
04da8f887b Update dependency pghero to v3.4.1 (#29144)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-13 20:03:00 +01:00
renovate[bot]
d9d0a6ef33 Update dependency irb to v1.11.2 (#29135)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-13 20:03:00 +01:00
renovate[bot]
93b365bfc0 Update dependency webmock to v3.20.0 (#29120)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-13 20:03:00 +01:00
Claire
e3c4e90646
Fix new list button being blank (#2616) 2024-02-13 12:48:01 +01:00
Claire
084d051e6c
Merge pull request #2608 from ClearlyClaire/glitch-soc/refactor/monolithic-components-css
Merge SCSS in a single `components.scss` file
2024-02-12 22:18:55 +01:00
Claire
c249c10f74 Fix account suggestion size inconsistency with upstream 2024-02-11 21:55:36 +01:00
Claire
d391e01b59 Revert notification bar color for now 2024-02-08 21:12:57 +01:00
Claire
3f89cec3c9 Further reduce differences with upstream 2024-02-08 19:52:03 +01:00
Claire
f6f62002c7 Remove leftovers from glitch-soc's layout option 2024-02-08 19:21:35 +01:00
Claire
189b70cd6a Merge SCSS in a single components.scss file 2024-02-08 18:50:38 +01:00
Claire
8c76a208ed
Merge pull request #2607 from ClearlyClaire/glitch-soc/cherry-pick-upstream
Cherry-pick upstream changes
2024-02-06 21:56:01 +01:00
Eugen Rochko
65eb943b9d Fix confirmation e-mails when signing up through an app (#29064) 2024-02-06 21:00:33 +01:00
Claire
19f1ffe287 Fix self-destruct schedule not actually replacing initial schedule (#29049) 2024-02-06 21:00:09 +01:00
renovate[bot]
5ea36a3606 Update dependency brakeman to v6.1.2 (#29062)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-06 20:59:51 +01:00
renovate[bot]
b27cad27c2 Update dependency bootsnap to '~> 1.18.0' (#29019)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-06 20:59:51 +01:00
renovate[bot]
63f1f1465a Update dependency tzinfo-data to v1.2024.1 (#29052)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-06 20:59:51 +01:00
Matt Jankowski
4cd00c0dd9 Update nsa gem to version 0.3.0 (#29065) 2024-02-06 20:59:51 +01:00
renovate[bot]
c6f7e3a1fb Update dependency haml_lint to v0.56.0 (#29082)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-06 20:59:51 +01:00
renovate[bot]
93aa783aa1 Update dependency nokogiri to v1.16.2 [SECURITY] (#29106)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-06 20:59:51 +01:00
renovate[bot]
868333c86f Update dependency capybara to v3.40.0 (#28966)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-06 20:59:51 +01:00
renovate[bot]
ac49514bd6 Update dependency chewy to v7.5.1 (#29018)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-06 20:59:51 +01:00
github-actions[bot]
a2611d782c
New Crowdin Translations (automated) (#2588)
* New Crowdin translations

* Fix bogus translation files

---------

Co-authored-by: GitHub Actions <noreply@github.com>
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
2024-02-06 20:45:07 +01:00
JS Moore
541cbdd963
Add env variable support for number of followable hashtags in feed column (#2500)
* Add env variable support for number of followable hashtags in feed column.

* Add a note about performance concerns for higher values.

See discussion in https://github.com/glitch-soc/mastodon/pull/2500

* Update .devcontainer/docker-compose.yml

---------

Co-authored-by: Claire <claire.github-309c@sitedethib.com>
2024-02-06 20:23:36 +01:00
Essem
08e511cecb
Fix doodle modal icons (#2597) 2024-02-06 20:22:42 +01:00
Claire
5bc39b3196 Fix build-security docker tags 2024-02-01 20:30:35 +01:00
Claire
c3936cbbe3 Temporary hack to correctly tag the security docker image… 2024-02-01 18:40:40 +01:00
Aaron Brady
970320d73c
Restore -streaming suffix for security builds (#2602) 2024-02-01 17:20:08 +01:00
84 changed files with 10518 additions and 10570 deletions

View File

@ -251,6 +251,11 @@ SMTP_FROM_ADDRESS=notifications@example.com
# Maximum allowed character count
MAX_TOOT_CHARS=500
# Maximum allowed hashtags to follow in a feed column
# Note that setting this value higher may cause significant
# database load
MAX_FEED_HASHTAGS=4
# Maximum number of pinned posts
MAX_PINNED_TOOTS=5

View File

@ -36,7 +36,7 @@ jobs:
tags: |
type=raw,value=edge
type=raw,value=nightly
type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }}
type=raw,value=${{ needs.compute-suffix.outputs.prerelease }}
secrets: inherit
build-image-streaming:
@ -48,7 +48,7 @@ jobs:
use_native_arm64_builder: false
cache: false
push_to_images: |
ghcr.io/${{ github.repository_owner }}/mastodon
ghcr.io/${{ github.repository_owner }}/mastodon-streaming
version_prerelease: ${{ needs.compute-suffix.outputs.prerelease }}
labels: |
org.opencontainers.image.description=Nightly build image used for testing purposes
@ -57,5 +57,5 @@ jobs:
tags: |
type=raw,value=edge
type=raw,value=nightly
type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }}
type=raw,value=${{ needs.compute-suffix.outputs.prerelease }}
secrets: inherit

View File

@ -2,6 +2,101 @@
All notable changes to this project will be documented in this file.
## [4.2.7] - 2024-02-16
### Fixed
- Fix OmniAuth tests and edge cases in error handling ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29201), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/29207))
- Fix new installs by upgrading to the latest release of the `nsa` gem, instead of a no longer existing commit ([mjankowski](https://github.com/mastodon/mastodon/pull/29065))
### Security
- Fix insufficient checking of remote posts ([GHSA-jhrq-qvrm-qr36](https://github.com/mastodon/mastodon/security/advisories/GHSA-jhrq-qvrm-qr36))
## [4.2.6] - 2024-02-14
### Security
- Update the `sidekiq-unique-jobs` dependency (see [GHSA-cmh9-rx85-xj38](https://github.com/mhenrixon/sidekiq-unique-jobs/security/advisories/GHSA-cmh9-rx85-xj38))
In addition, we have disabled the web interface for `sidekiq-unique-jobs` out of caution.
If you need it, you can re-enable it by setting `ENABLE_SIDEKIQ_UNIQUE_JOBS_UI=true`.
If you only need to clear all locks, you can now use `bundle exec rake sidekiq_unique_jobs:delete_all_locks`.
- Update the `nokogiri` dependency (see [GHSA-xc9x-jj77-9p9j](https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-xc9x-jj77-9p9j))
- Disable administrative Doorkeeper routes ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/29187))
- Fix ongoing streaming sessions not being invalidated when applications get deleted in some cases ([GHSA-7w3c-p9j8-mq3x](https://github.com/mastodon/mastodon/security/advisories/GHSA-7w3c-p9j8-mq3x))
In some rare cases, the streaming server was not notified of access tokens revocation on application deletion.
- Change external authentication behavior to never reattach a new identity to an existing user by default ([GHSA-vm39-j3vx-pch3](https://github.com/mastodon/mastodon/security/advisories/GHSA-vm39-j3vx-pch3))
Up until now, Mastodon has allowed new identities from external authentication providers to attach to an existing local user based on their verified e-mail address.
This allowed upgrading users from a database-stored password to an external authentication provider, or move from one authentication provider to another.
However, this behavior may be unexpected, and means that when multiple authentication providers are configured, the overall security would be that of the least secure authentication provider.
For these reasons, this behavior is now locked under the `ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH` environment variable.
In addition, regardless of this environment variable, Mastodon will refuse to attach two identities from the same authentication provider to the same account.
## [4.2.5] - 2024-02-01
### Security
- Fix insufficient origin validation (CVE-2024-23832, [GHSA-3fjr-858r-92rw](https://github.com/mastodon/mastodon/security/advisories/GHSA-3fjr-858r-92rw))
## [4.2.4] - 2024-01-24
### Fixed
- Fix error when processing remote files with unusually long names ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28823))
- Fix processing of compacted single-item JSON-LD collections ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28816))
- Retry 401 errors on replies fetching ([ShadowJonathan](https://github.com/mastodon/mastodon/pull/28788))
- Fix `RecordNotUnique` errors in LinkCrawlWorker ([tribela](https://github.com/mastodon/mastodon/pull/28748))
- Fix Mastodon not correctly processing HTTP Signatures with query strings ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28443), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/28476))
- Fix potential redirection loop of streaming endpoint ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28665))
- Fix streaming API redirection ignoring the port of `streaming_api_base_url` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28558))
- Fix error when processing link preview with an array as `inLanguage` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28252))
- Fix unsupported time zone or locale preventing sign-up ([Gargron](https://github.com/mastodon/mastodon/pull/28035))
- Fix "Hide these posts from home" list setting not refreshing when switching lists ([brianholley](https://github.com/mastodon/mastodon/pull/27763))
- Fix missing background behind dismissable banner in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/27479))
- Fix line wrapping of language selection button with long locale codes ([gunchleoc](https://github.com/mastodon/mastodon/pull/27100), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27127))
- Fix `Undo Announce` activity not being sent to non-follower authors ([MitarashiDango](https://github.com/mastodon/mastodon/pull/18482))
- Fix N+1s because of association preloaders not actually getting called ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28339))
- Fix empty column explainer getting cropped under certain conditions ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28337))
- Fix `LinkCrawlWorker` error when encountering empty OEmbed response ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28268))
- Fix call to inefficient `delete_matched` cache method in domain blocks ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28367))
### Security
- Add rate-limit of TOTP authentication attempts at controller level ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28801))
## [4.2.3] - 2023-12-05
### Fixed
- Fix dependency on `json-canonicalization` version that has been made unavailable since last release
## [4.2.2] - 2023-12-04
### Changed
- Change dismissed banners to be stored server-side ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27055))
- Change GIF max matrix size error to explicitly mention GIF files ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27927))
- Change `Follow` activities delivery to bypass availability check ([ShadowJonathan](https://github.com/mastodon/mastodon/pull/27586))
- Change single-column navigation notice to be displayed outside of the logo container ([renchap](https://github.com/mastodon/mastodon/pull/27462), [renchap](https://github.com/mastodon/mastodon/pull/27476))
- Change Content-Security-Policy to be tighter on media paths ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26889))
- Change post language code to include country code when relevant ([gunchleoc](https://github.com/mastodon/mastodon/pull/27099), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27207))
### Fixed
- Fix upper border radius of onboarding columns ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27890))
- Fix incoming status creation date not being restricted to standard ISO8601 ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27655), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/28081))
- Fix some posts from threads received out-of-order sometimes not being inserted into timelines ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27653))
- Fix posts from force-sensitized accounts being able to trend ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27620))
- Fix error when trying to delete already-deleted file with OpenStack Swift ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27569))
- Fix batch attachment deletion when using OpenStack Swift ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27554))
- Fix processing LDSigned activities from actors with unknown public keys ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27474))
- Fix error and incorrect URLs in `/api/v1/accounts/:id/featured_tags` for remote accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27459))
- Fix report processing notice not mentioning the report number when performing a custom action ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27442))
- Fix handling of `inLanguage` attribute in preview card processing ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27423))
- Fix own posts being removed from home timeline when unfollowing a used hashtag ([kmycode](https://github.com/mastodon/mastodon/pull/27391))
- Fix some link anchors being recognized as hashtags ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27271), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27584))
- Fix format-dependent redirects being cached regardless of requested format ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27634))
## [4.2.1] - 2023-10-10
### Added

View File

@ -26,7 +26,7 @@ gem 'blurhash', '~> 0.1'
gem 'active_model_serializers', '~> 0.10'
gem 'addressable', '~> 2.8'
gem 'bootsnap', '~> 1.17.0', require: false
gem 'bootsnap', '~> 1.18.0', require: false
gem 'browser'
gem 'charlock_holmes', '~> 0.7.7'
gem 'chewy', '~> 7.3'
@ -63,7 +63,7 @@ gem 'kaminari', '~> 1.2'
gem 'link_header', '~> 0.0'
gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar'
gem 'nokogiri', '~> 1.15'
gem 'nsa', github: 'jhawthorn/nsa', ref: 'e020fcc3a54d993ab45b7194d89ab720296c111b'
gem 'nsa'
gem 'oj', '~> 3.14'
gem 'ox', '~> 2.14'
gem 'parslet'

View File

@ -7,17 +7,6 @@ GIT
hkdf (~> 0.2)
jwt (~> 2.0)
GIT
remote: https://github.com/jhawthorn/nsa.git
revision: e020fcc3a54d993ab45b7194d89ab720296c111b
ref: e020fcc3a54d993ab45b7194d89ab720296c111b
specs:
nsa (0.2.8)
activesupport (>= 4.2, < 7.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
sidekiq (>= 3.5)
statsd-ruby (~> 1.4, >= 1.4.0)
GEM
remote: https://rubygems.org/
specs:
@ -155,9 +144,9 @@ GEM
binding_of_caller (1.0.0)
debug_inspector (>= 0.0.1)
blurhash (0.1.7)
bootsnap (1.17.1)
bootsnap (1.18.3)
msgpack (~> 1.2)
brakeman (6.1.1)
brakeman (6.1.2)
racc
browser (5.3.1)
brpoplpush-redis_script (0.1.3)
@ -167,11 +156,11 @@ GEM
bundler-audit (0.9.1)
bundler (>= 1.2.0, < 3)
thor (~> 1.0)
capybara (3.39.2)
capybara (3.40.0)
addressable
matrix
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
nokogiri (~> 1.11)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
@ -180,7 +169,7 @@ GEM
activesupport
cbor (0.5.9.6)
charlock_holmes (0.7.7)
chewy (7.5.0)
chewy (7.5.1)
activesupport (>= 5.2)
elasticsearch (>= 7.12.0, < 7.14.0)
elasticsearch-dsl
@ -193,7 +182,8 @@ GEM
cose (1.3.0)
cbor (~> 0.5.9)
openssl-signature_algorithm (~> 1.0)
crack (0.4.5)
crack (0.4.6)
bigdecimal
rexml
crass (1.0.6)
css_parser (1.14.0)
@ -319,13 +309,13 @@ GEM
activesupport (>= 5.1)
haml (>= 4.0.6)
railties (>= 5.1)
haml_lint (0.55.0)
haml_lint (0.56.0)
haml (>= 5.0)
parallel (~> 1.10)
rainbow
rubocop (>= 1.0)
sysexits (~> 1.1)
hashdiff (1.0.1)
hashdiff (1.1.0)
hashie (5.0.0)
hcaptcha (7.1.0)
json
@ -361,7 +351,7 @@ GEM
terminal-table (>= 1.5.1)
idn-ruby (0.1.5)
io-console (0.7.2)
irb (1.11.1)
irb (1.11.2)
rdoc
reline (>= 0.4.2)
jmespath (1.6.2)
@ -465,9 +455,14 @@ GEM
net-smtp (0.4.0.1)
net-protocol
nio4r (2.5.9)
nokogiri (1.16.0)
nokogiri (1.16.2)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nsa (0.3.0)
activesupport (>= 4.2, < 7.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
sidekiq (>= 3.5)
statsd-ruby (~> 1.4, >= 1.4.0)
oj (3.16.3)
bigdecimal (>= 3.0)
omniauth (2.1.1)
@ -510,8 +505,8 @@ GEM
parslet (2.0.0)
pastel (0.8.0)
tty-color (~> 0.5)
pg (1.5.4)
pghero (3.4.0)
pg (1.5.5)
pghero (3.4.1)
activerecord (>= 6)
posix-spawn (0.3.15)
premailer (1.21.0)
@ -712,7 +707,7 @@ GEM
rufus-scheduler (~> 3.2)
sidekiq (>= 6, < 8)
tilt (>= 1.4.0)
sidekiq-unique-jobs (7.1.31)
sidekiq-unique-jobs (7.1.33)
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
concurrent-ruby (~> 1.0, >= 1.0.5)
redis (< 5.0)
@ -771,7 +766,7 @@ GEM
unf (~> 0.1.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
tzinfo-data (1.2023.4)
tzinfo-data (1.2024.1)
tzinfo (>= 1.0.0)
unf (0.1.4)
unf_ext
@ -798,7 +793,7 @@ GEM
webfinger (1.2.0)
activesupport
httpclient (>= 2.4)
webmock (3.19.1)
webmock (3.20.0)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
@ -829,7 +824,7 @@ DEPENDENCIES
better_errors (~> 2.9)
binding_of_caller (~> 1.0)
blurhash (~> 0.1)
bootsnap (~> 1.17.0)
bootsnap (~> 1.18.0)
brakeman (~> 6.0)
browser
bundler-audit (~> 0.9)
@ -886,7 +881,7 @@ DEPENDENCIES
net-http (~> 0.4.0)
net-ldap (~> 0.18)
nokogiri (~> 1.15)
nsa!
nsa
oj (~> 3.14)
omniauth (~> 2.0)
omniauth-cas (~> 3.0.0.beta.1)

View File

@ -7,7 +7,7 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def self.provides_callback_for(provider)
define_method provider do
@provider = provider
@user = User.find_for_oauth(request.env['omniauth.auth'], current_user)
@user = User.find_for_omniauth(request.env['omniauth.auth'], current_user)
if @user.persisted?
record_login_activity
@ -17,6 +17,9 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
session["devise.#{provider}_data"] = request.env['omniauth.auth']
redirect_to new_user_registration_url
end
rescue ActiveRecord::RecordInvalid
flash[:alert] = I18n.t('devise.failure.omniauth_user_creation_failure') if is_navigational_format?
redirect_to new_user_session_url
end
end

View File

@ -174,7 +174,19 @@ module JsonLdHelper
build_request(uri, on_behalf_of, options: request_options).perform do |response|
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) || !raise_on_temporary_error
body_to_json(response.body_with_limit) if response.code == 200
body_to_json(response.body_with_limit) if response.code == 200 && valid_activitypub_content_type?(response)
end
end
def valid_activitypub_content_type?(response)
return true if response.mime_type == 'application/activity+json'
# When the mime type is `application/ld+json`, we need to check the profile,
# but `http.rb` does not parse it for us.
return false unless response.mime_type == 'application/ld+json'
response.headers[HTTP::Headers::CONTENT_TYPE]&.split(';')&.map(&:strip)&.any? do |str|
str.start_with?('profile="') && str[9...-1].split.include?('https://www.w3.org/ns/activitystreams')
end
end

View File

@ -15,7 +15,7 @@ export default class AutosuggestAccount extends ImmutablePureComponent {
return (
<div className='autosuggest-account' title={account.get('acct')}>
<div className='autosuggest-account-icon'><Avatar account={account} size={24} /></div>
<div className='autosuggest-account-icon'><Avatar account={account} size={18} /></div>
<DisplayName account={account} inline />
</div>
);

View File

@ -70,7 +70,6 @@ class ComposeForm extends ImmutablePureComponent {
singleColumn: PropTypes.bool,
lang: PropTypes.string,
advancedOptions: ImmutablePropTypes.map,
layout: PropTypes.string,
media: ImmutablePropTypes.list,
sideArm: PropTypes.string,
sensitive: PropTypes.bool,
@ -259,7 +258,6 @@ class ComposeForm extends ImmutablePureComponent {
intl,
advancedOptions,
isSubmitting,
layout,
onChangeSpoilerness,
onPaste,
privacy,
@ -313,7 +311,7 @@ class ComposeForm extends ImmutablePureComponent {
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
onSuggestionSelected={this.onSuggestionSelected}
onPaste={onPaste}
autoFocus={!showSearch && !isMobile(window.innerWidth, layout)}
autoFocus={!showSearch && !isMobile(window.innerWidth)}
lang={this.props.lang}
>
<TextareaIcons advancedOptions={advancedOptions} />

View File

@ -38,8 +38,8 @@ export default class NavigationBar extends ImmutablePureComponent {
{ profileLink !== undefined && (
<a
className='edit'
href={profileLink}
className='navigation-bar__profile-edit'
><FormattedMessage id='navigation_bar.edit_profile' defaultMessage='Edit profile' /></a>
)}
</div>

View File

@ -76,7 +76,7 @@ class SearchResults extends ImmutablePureComponent {
return (
<div className='drawer--results'>
<div className='search-results'>
<header className='search-results__header'>
<Icon id='search' icon={SearchIcon} />
<FormattedMessage id='explore.search_results' defaultMessage='Search results' />

View File

@ -71,7 +71,6 @@ const mapStateToProps = state => ({
isInReply: state.getIn(['compose', 'in_reply_to']) !== null,
lang: state.getIn(['compose', 'language']),
advancedOptions: state.getIn(['compose', 'advanced_options']),
layout: state.getIn(['local_settings', 'layout']),
media: state.getIn(['compose', 'media_attachments']),
sideArm: sideArmPrivacy(state),
sensitive: state.getIn(['compose', 'sensitive']),

View File

@ -9,6 +9,8 @@ import { NonceProvider } from 'react-select';
import AsyncSelect from 'react-select/async';
import Toggle from 'react-toggle';
import { maxFeedHashtags } from 'flavours/glitch/initial_state';
import SettingToggle from '../../notifications/components/setting_toggle';
const messages = defineMessages({
@ -46,9 +48,9 @@ class ColumnSettings extends PureComponent {
onSelect = mode => value => {
const oldValue = this.tags(mode);
// Prevent changes that add more than 4 tags, but allow removing
// tags that were already added before
if ((value.length > 4) && !(value < oldValue)) {
// Prevent changes that add more than the number of configured
// tags, but allow removing tags that were already added before
if ((value.length > maxFeedHashtags) && !(value < oldValue)) {
return;
}

View File

@ -68,7 +68,7 @@ class NewListForm extends PureComponent {
<Button
disabled={disabled || !value}
title={title}
text={title}
onClick={this.handleClick}
/>
</form>

View File

@ -9,6 +9,10 @@ import { connect } from 'react-redux';
import Atrament from 'atrament'; // the doodling library
import { debounce, mapValues } from 'lodash';
import ColorsIcon from '@/material-icons/400-24px/colors.svg?react';
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
import UndoIcon from '@/material-icons/400-24px/undo.svg?react';
import { doodleSet, uploadCompose } from 'flavours/glitch/actions/compose';
import { Button } from 'flavours/glitch/components/button';
import { IconButton } from 'flavours/glitch/components/icon_button';
@ -584,10 +588,10 @@ class DoodleModal extends ImmutablePureComponent {
</div>
</div>
<div className='doodle-toolbar'>
<IconButton icon='pencil' title='Draw' label='Draw' onClick={this.setModeDraw} size={18} active={this.mode === 'draw'} inverted />
<IconButton icon='bath' title='Fill' label='Fill' onClick={this.setModeFill} size={18} active={this.mode === 'fill'} inverted />
<IconButton icon='undo' title='Undo' label='Undo' onClick={this.undo} size={18} inverted />
<IconButton icon='trash' title='Clear' label='Clear' onClick={this.handleClearBtn} size={18} inverted />
<IconButton icon='pencil' iconComponent={EditIcon} title='Draw' label='Draw' onClick={this.setModeDraw} size={18} active={this.mode === 'draw'} inverted />
<IconButton icon='bath' iconComponent={ColorsIcon} title='Fill' label='Fill' onClick={this.setModeFill} size={18} active={this.mode === 'fill'} inverted />
<IconButton icon='undo' iconComponent={UndoIcon} title='Undo' label='Undo' onClick={this.undo} size={18} inverted />
<IconButton icon='trash' iconComponent={DeleteIcon} title='Clear' label='Clear' onClick={this.handleClearBtn} size={18} inverted />
</div>
<div className='doodle-palette'>
{

View File

@ -602,18 +602,7 @@ class UI extends PureComponent {
const { draggingOver } = this.state;
const { children, isWide, location, dropdownMenuIsOpen, layout, moved } = this.props;
const columnsClass = layout => {
switch (layout) {
case 'single':
return 'single-column';
case 'multiple':
return 'multi-columns';
default:
return 'auto-columns';
}
};
const className = classNames('ui', columnsClass(layout), {
const className = classNames('ui', {
'wide': isWide,
'system-font': this.props.systemFontUi,
'hicolor-privacy-icons': this.props.hicolorPrivacyIcons,

View File

@ -67,6 +67,7 @@ export const hasMultiColumnPath = initialPath === '/'
* @property {InitialStateMeta} meta
* @property {object} local_settings
* @property {number} max_toot_chars
* @property {number} max_feed_hashtags
* @property {number} poll_limits
*/
@ -130,6 +131,7 @@ export const sso_redirect = getMeta('sso_redirect');
// Glitch-soc-specific settings
export const maxChars = (initialState && initialState.max_toot_chars) || 500;
export const maxFeedHashtags = (initialState && initialState.max_feed_hashtags) || 4;
export const favouriteModal = getMeta('favourite_modal');
export const pollLimits = (initialState && initialState.poll_limits);
export const defaultContentType = getMeta('default_content_type');

View File

@ -1,4 +1,51 @@
{
"about.fork_disclaimer": "Glitch-soc adalah perangkat lunak sumber terbuka yang merupakan fork dari Mastodon.",
"account.disclaimer_full": "Informasi di bawah ini mungkin tidak mencerminkan profil pengguna secara lengkap.",
"account.follows": "Mengikuti",
"account.joined": "Bergabung {date}",
"account.suspended_disclaimer_full": "Pengguna ini telah ditangguhkan oleh moderator.",
"account.view_full_profile": "Tampilkan profil lengkap",
"advanced_options.icon_title": "Opsi lanjutan",
"advanced_options.local-only.long": "Jangan mengunggah ke instance lain",
"advanced_options.local-only.short": "Hanya lokal",
"advanced_options.local-only.tooltip": "Postingan ini hanya untuk lokal",
"advanced_options.threaded_mode.long": "Secara otomatis membuka balasan pada postingan",
"advanced_options.threaded_mode.short": "Mode Utasan",
"advanced_options.threaded_mode.tooltip": "Mode utasan dinyalakan",
"boost_modal.missing_description": "Toot ini berisi beberapa media tanpa deskripsi",
"column.favourited_by": "Disukai oleh",
"column.heading": "Lainnya",
"column.reblogged_by": "Dibagikan oleh",
"column.subheading": "Opsi lain-lain",
"column_header.profile": "Profil",
"column_subheading.lists": "Daftar",
"column_subheading.navigation": "Penelusuran",
"community.column_settings.allow_local_only": "Tampilkan toot lokal saja",
"compose.attach": "Lampirkan...",
"compose.attach.doodle": "Gambar sesuatu",
"compose.attach.upload": "Unggah file",
"compose.content-type.html": "HTML",
"compose.content-type.markdown": "Bahasa Markdown",
"compose.content-type.plain": "Teks biasa",
"compose_form.poll.multiple_choices": "Izinkan beberapa pilihan",
"compose_form.poll.single_choice": "Izinkan hanya satu pilihan",
"compose_form.spoiler": "Sembunyikan teks di balik peringatan",
"confirmation_modal.do_not_ask_again": "Jangan minta konfirmasi lagi",
"confirmations.deprecated_settings.confirm": "Gunakan preferensi Mastodon",
"confirmations.deprecated_settings.message": "Beberapa {app_settings} khusus perangkat Glitch-soc yang Anda gunakan telah digantikan oleh {preferences} Mastodon dan akan diganti:",
"confirmations.missing_media_description.confirm": "Tetap kirim",
"confirmations.missing_media_description.edit": "Sunting media",
"confirmations.missing_media_description.message": "Setidaknya satu lampiran media tidak memiliki deskripsi. Pertimbangkan untuk mendeskripsikan semua lampiran media untuk pengguna tunanetra sebelum mengirim toot Anda.",
"confirmations.unfilter.author": "Penulis",
"confirmations.unfilter.confirm": "Tampilkan",
"confirmations.unfilter.edit_filter": "Ubah saringan",
"content-type.change": "Jenis konten",
"direct.group_by_conversations": "Grupkan berdasarkan percakapan",
"endorsed_accounts_editor.endorsed_accounts": "Akun pilihan",
"favourite_modal.combo": "Anda dapat menekan {combo} untuk melewati ini lain kali",
"firehose.column_settings.allow_local_only": "Tampilkan postingan khusus lokal di \"Semua\"",
"home.column_settings.advanced": "Lanjutan",
"home.column_settings.filter_regex": "Saring dengan ekspresi reguler",
"settings.content_warnings": "Content warnings",
"settings.preferences": "Preferences"
}

View File

@ -1,4 +1,52 @@
{
"account.follows": "Följer",
"account.joined": "Gick med {date}",
"account.suspended_disclaimer_full": "Denna användare har stängts av av en moderator.",
"account.view_full_profile": "Visa full profil",
"advanced_options.icon_title": "Avancerade inställningar",
"advanced_options.local-only.long": "Lägg inte ut på andra instanser",
"advanced_options.local-only.short": "Endast lokalt",
"advanced_options.local-only.tooltip": "Detta inlägg är endast tillgängligt lokalt",
"advanced_options.threaded_mode.long": "Öppnar automatiskt ett svar vid publicering",
"advanced_options.threaded_mode.short": "Tråd-läge",
"advanced_options.threaded_mode.tooltip": "Tråd-läge på",
"boost_modal.missing_description": "Denna toot innehåller viss media utan beskrivning",
"column.favourited_by": "Favoritmarkerad av",
"column.heading": "Övrigt",
"column.reblogged_by": "Boostad av",
"column.subheading": "Övriga val",
"column_header.profile": "Profil",
"column_subheading.lists": "Listor",
"column_subheading.navigation": "Navigering",
"community.column_settings.allow_local_only": "Visa endast lokala toots",
"compose.attach": "Bifoga...",
"compose.attach.doodle": "Rita något",
"compose.attach.upload": "Ladda upp en fil",
"compose.content-type.html": "HTML",
"compose.content-type.markdown": "Markdown",
"compose.content-type.plain": "Klartext",
"compose_form.poll.multiple_choices": "Tillåt flera val",
"compose_form.poll.single_choice": "Tillåt ett val",
"compose_form.spoiler": "Göm text bakom varning",
"confirmation_modal.do_not_ask_again": "Fråga mig inte igen",
"confirmations.deprecated_settings.confirm": "Använd Mastodon-preferenser",
"confirmations.deprecated_settings.message": "Några av de glitch-soc-enhetsspecifika {app_settings} som du använder har ersatts av Mastodon-{preferences} och kommer att åsidosättas:",
"confirmations.missing_media_description.confirm": "Lägg ut ändå",
"confirmations.missing_media_description.edit": "Redigera media",
"confirmations.missing_media_description.message": "Minst en mediebilaga saknar beskrivning. Överväg att beskriva all media för synskadade innan du skickar din toot.",
"confirmations.unfilter.author": "Användare",
"confirmations.unfilter.confirm": "Visa",
"confirmations.unfilter.edit_filter": "Redigera filter",
"confirmations.unfilter.filters": "Matchande {count, plural, one {filter} other {filters}}",
"content-type.change": "Innehållstyp",
"direct.group_by_conversations": "Sortera efter konversation",
"endorsed_accounts_editor.endorsed_accounts": "Utvalda konton",
"favourite_modal.combo": "Du kan trycka på {combo} för att skippa detta nästa gång",
"firehose.column_settings.allow_local_only": "Visa endast lokala inlägg i \"Alla\"",
"home.column_settings.advanced": "Avancerat",
"home.column_settings.filter_regex": "Filtrera bort med reguljära uttryck",
"home.column_settings.show_direct": "Visa privata omnämningar",
"home.settings": "Kolumninställningar",
"settings.content_warnings": "Content warnings",
"settings.preferences": "Preferences"
}

View File

@ -1,5 +1,5 @@
import 'packs/public-path';
import Rails from '@rails/ujs';
import { start } from '@rails/ujs';
import 'flavours/glitch/styles/modern.scss';
start();

View File

@ -14,9 +14,7 @@ const initialState = ImmutableMap({
export default function meta(state = initialState, action) {
switch(action.type) {
case STORE_HYDRATE:
return state.merge(action.state.get('meta'))
.set('permissions', action.state.getIn(['role', 'permissions']))
.set('layout', layoutFromWindow(action.state.getIn(['local_settings', 'layout'])));
return state.merge(action.state.get('meta')).set('permissions', action.state.getIn(['role', 'permissions']));
case changeLayout.type:
return state.set('layout', action.payload.layout);
default:

View File

@ -10,37 +10,6 @@
background-size: $size $size;
}
@mixin single-column($media, $parent: '&') {
.auto-columns #{$parent} {
@media #{$media} {
@content;
}
}
.single-column #{$parent} {
@content;
}
}
@mixin limited-single-column($media, $parent: '&') {
.auto-columns #{$parent},
.single-column #{$parent} {
@media #{$media} {
@content;
}
}
}
@mixin multi-columns($media, $parent: '&') {
.auto-columns #{$parent} {
@media #{$media} {
@content;
}
}
.multi-columns #{$parent} {
@content;
}
}
@mixin fullwidth-gallery {
&.full-width {
margin-left: -14px;

File diff suppressed because it is too large Load Diff

View File

@ -1,298 +0,0 @@
.image {
position: relative;
overflow: hidden;
&__preview {
position: absolute;
top: 0;
inset-inline-start: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
&.loaded &__preview {
display: none;
}
img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
border: 0;
background: transparent;
opacity: 0;
}
&.loaded img {
opacity: 1;
}
}
.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;
.version {
white-space: nowrap;
}
strong {
font-weight: 500;
}
a {
color: $dark-text-color;
text-decoration: underline;
&:hover,
&:focus,
&:active {
text-decoration: none;
}
}
}
}
.about {
padding: 20px;
@media screen and (min-width: $no-gap-breakpoint) {
border-radius: 4px;
}
&__footer {
color: $dark-text-color;
text-align: center;
font-size: 15px;
line-height: 22px;
margin-top: 20px;
}
&__header {
margin-bottom: 30px;
&__hero {
width: 100%;
height: auto;
aspect-ratio: 1.9;
background: lighten($ui-base-color, 4%);
border-radius: 8px;
margin-bottom: 30px;
}
h1,
p {
text-align: center;
}
h1 {
font-size: 24px;
line-height: 1.5;
font-weight: 700;
margin-bottom: 10px;
}
p {
font-size: 16px;
line-height: 24px;
font-weight: 400;
color: $darker-text-color;
}
}
&__meta {
background: lighten($ui-base-color, 4%);
border-radius: 4px;
display: flex;
margin-bottom: 30px;
font-size: 15px;
&__column {
box-sizing: border-box;
width: 50%;
padding: 20px;
}
&__divider {
width: 0;
border: 0;
border-style: solid;
border-color: lighten($ui-base-color, 8%);
border-left-width: 1px;
min-height: calc(100% - 60px);
flex: 0 0 auto;
}
h4 {
font-size: 15px;
text-transform: uppercase;
color: $darker-text-color;
font-weight: 500;
margin-bottom: 20px;
}
@media screen and (width <= 600px) {
display: block;
h4 {
text-align: center;
}
&__column {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
&__divider {
min-height: 0;
width: 100%;
border-left-width: 0;
border-top-width: 1px;
}
}
.layout-multiple-columns & {
display: block;
h4 {
text-align: center;
}
&__column {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
&__divider {
min-height: 0;
width: 100%;
border-left-width: 0;
border-top-width: 1px;
}
}
}
&__mail {
color: $primary-text-color;
text-decoration: none;
font-weight: 500;
&:hover,
&:focus,
&:active {
text-decoration: underline;
}
}
.link-footer {
padding: 0;
margin-top: 60px;
text-align: center;
font-size: 15px;
line-height: 22px;
@media screen and (min-width: $no-gap-breakpoint) {
display: none;
}
}
.account {
padding: 0;
border: 0;
}
.account__avatar-wrapper {
margin-inline-start: 0;
}
.account__relationship {
display: none;
}
&__section {
margin-bottom: 10px;
&__title {
display: flex;
align-items: center;
gap: 6px;
font-size: 17px;
font-weight: 600;
line-height: 22px;
padding: 20px;
border-radius: 4px;
background: lighten($ui-base-color, 4%);
color: $highlight-text-color;
cursor: pointer;
}
&.active &__title {
border-radius: 4px 4px 0 0;
}
&__body {
border: 1px solid lighten($ui-base-color, 4%);
border-top: 0;
padding: 20px;
font-size: 15px;
line-height: 22px;
}
}
&__domain-blocks {
margin-top: 30px;
background: darken($ui-base-color, 4%);
border: 1px solid lighten($ui-base-color, 4%);
border-radius: 4px;
&__domain {
border-bottom: 1px solid lighten($ui-base-color, 4%);
padding: 10px;
font-size: 15px;
color: $darker-text-color;
&:nth-child(2n) {
background: darken($ui-base-color, 2%);
}
&:last-child {
border-bottom: 0;
}
&__header {
display: flex;
gap: 10px;
justify-content: space-between;
font-weight: 500;
margin-bottom: 4px;
}
h6 {
color: $secondary-text-color;
font-size: inherit;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
p {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}

View File

@ -1,841 +0,0 @@
.account {
padding: 10px;
border-bottom: 1px solid lighten($ui-base-color, 8%);
color: inherit;
text-decoration: none;
.account__display-name {
flex: 1 1 auto;
display: flex;
align-items: center;
gap: 10px;
color: $darker-text-color;
overflow: hidden;
text-decoration: none;
font-size: 14px;
.display-name {
margin-bottom: 4px;
}
.display-name strong {
display: inline;
}
}
&--minimal {
.account__display-name {
.display-name {
margin-bottom: 0;
}
.display-name strong {
display: block;
}
}
}
&__note {
font-size: 14px;
font-weight: 400;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
margin-top: 10px;
color: $darker-text-color;
&--missing {
color: $dark-text-color;
}
p {
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
}
a {
color: inherit;
&:hover,
&:focus,
&:active {
text-decoration: none;
}
}
}
}
.account__wrapper {
display: flex;
gap: 10px;
align-items: center;
}
.account__avatar-wrapper {
float: left;
}
.account__avatar {
@include avatar-radius;
display: block;
position: relative;
overflow: hidden;
img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
&-inline {
display: inline-block;
vertical-align: middle;
margin-inline-end: 5px;
}
&-composite {
@include avatar-radius;
overflow: hidden;
position: relative;
& > div {
@include avatar-radius;
float: left;
position: relative;
box-sizing: border-box;
}
.account__avatar {
width: 100% !important;
height: 100% !important;
}
&__label {
display: block;
position: absolute;
top: 50%;
inset-inline-start: 50%;
transform: translate(-50%, -50%);
color: $primary-text-color;
text-shadow: 1px 1px 2px $base-shadow-color;
font-weight: 700;
font-size: 15px;
}
}
}
.account__avatar-overlay {
position: relative;
&-overlay {
position: absolute;
bottom: 0;
inset-inline-end: 0;
z-index: 1;
}
}
.account__relationship {
white-space: nowrap;
display: flex;
align-items: center;
gap: 4px;
}
.account__header__wrapper {
flex: 0 0 auto;
background: lighten($ui-base-color, 4%);
}
.account__disclaimer {
display: flex;
padding: 10px;
gap: 5px;
color: $dark-text-color;
align-items: center;
strong {
font-weight: 500;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
a {
font-weight: 500;
color: inherit;
text-decoration: underline;
&:hover,
&:focus,
&:active {
text-decoration: none;
}
}
}
.account__action-bar {
border-top: 1px solid lighten($ui-base-color, 8%);
border-bottom: 1px solid lighten($ui-base-color, 8%);
line-height: 36px;
overflow: hidden;
flex: 0 0 auto;
display: flex;
}
.account__action-bar-links {
display: flex;
flex: 1 1 auto;
line-height: 18px;
text-align: center;
}
.account__action-bar__tab {
text-decoration: none;
overflow: hidden;
flex: 0 1 100%;
border-inline-start: 1px solid lighten($ui-base-color, 8%);
padding: 10px 0;
border-bottom: 4px solid transparent;
&:first-child {
border-inline-start: 0;
}
&.active {
border-bottom: 4px solid $ui-highlight-color;
}
& > span {
display: block;
text-transform: uppercase;
font-size: 11px;
color: $darker-text-color;
}
strong {
display: block;
font-size: 15px;
font-weight: 500;
color: $primary-text-color;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
abbr {
color: $highlight-text-color;
}
}
.account-authorize {
padding: 14px 10px;
.detailed-status__display-name {
display: block;
margin-bottom: 15px;
overflow: hidden;
}
}
.account-authorize__avatar {
float: left;
margin-inline-end: 10px;
}
.notification__report {
padding: 8px 10px;
padding-inline-start: 68px;
position: relative;
border-bottom: 1px solid lighten($ui-base-color, 8%);
min-height: 54px;
&__details {
display: flex;
justify-content: space-between;
align-items: center;
color: $darker-text-color;
font-size: 15px;
line-height: 22px;
strong {
font-weight: 500;
}
}
&__avatar {
position: absolute;
inset-inline-start: 10px;
top: 10px;
}
}
.notification__message {
margin-inline-start: 42px;
padding-top: 8px;
padding-inline-start: 26px;
cursor: default;
color: $darker-text-color;
font-size: 15px;
position: relative;
align-items: center;
.icon {
color: $highlight-text-color;
width: 18px;
height: 18px;
}
.icon-star {
color: $gold-star;
}
> span {
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
}
.account--panel {
background: lighten($ui-base-color, 4%);
border-top: 1px solid lighten($ui-base-color, 8%);
border-bottom: 1px solid lighten($ui-base-color, 8%);
display: flex;
flex-direction: row;
padding: 10px 0;
}
.account--panel__button,
.detailed-status__button {
flex: 1 1 auto;
text-align: center;
}
.relationship-tag {
color: $white;
margin-bottom: 4px;
display: block;
background-color: rgba($black, 0.45);
text-transform: uppercase;
font-size: 11px;
font-weight: 500;
padding: 4px;
border-radius: 4px;
opacity: 0.7;
&:hover {
opacity: 1;
}
}
.account-gallery__container {
display: flex;
flex-wrap: wrap;
padding: 4px 2px;
}
.account-gallery__item {
border: 0;
box-sizing: border-box;
display: block;
position: relative;
border-radius: 4px;
overflow: hidden;
margin: 2px;
&__icons {
position: absolute;
top: 50%;
inset-inline-start: 50%;
transform: translate(-50%, -50%);
font-size: 24px;
}
}
.notification__filter-bar,
.account__section-headline {
background: darken($ui-base-color, 4%);
border-bottom: 1px solid lighten($ui-base-color, 8%);
cursor: default;
display: flex;
flex-shrink: 0;
button {
background: transparent;
border: 0;
margin: 0;
}
button,
a {
display: block;
flex: 1 1 auto;
color: $darker-text-color;
padding: 15px 0;
font-size: 14px;
font-weight: 500;
text-align: center;
text-decoration: none;
position: relative;
&.active {
color: $primary-text-color;
&::before {
display: block;
content: '';
position: absolute;
bottom: -1px;
left: 0;
width: 100%;
height: 3px;
border-radius: 4px;
background: $highlight-text-color;
}
}
}
&.directory__section-headline {
background: darken($ui-base-color, 2%);
border-bottom-color: transparent;
a,
button {
&.active {
&::before {
display: none;
}
&::after {
border-color: transparent transparent darken($ui-base-color, 7%);
}
}
}
}
}
.account__moved-note {
padding: 14px 10px;
padding-bottom: 16px;
background: lighten($ui-base-color, 4%);
border-top: 1px solid lighten($ui-base-color, 8%);
border-bottom: 1px solid lighten($ui-base-color, 8%);
&__message {
position: relative;
margin-inline-start: 58px;
color: $dark-text-color;
padding: 8px 0;
padding-top: 0;
padding-bottom: 4px;
font-size: 14px;
> span {
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
}
&__icon-wrapper {
inset-inline-start: -26px;
position: absolute;
}
.detailed-status__display-avatar {
position: relative;
}
.detailed-status__display-name {
margin-bottom: 0;
}
}
.account__header__content {
color: $darker-text-color;
font-size: 14px;
font-weight: 400;
overflow: hidden;
word-break: normal;
word-wrap: break-word;
p {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
a {
color: inherit;
text-decoration: underline;
&:hover {
text-decoration: none;
}
}
}
.account__header {
overflow: hidden;
&.inactive {
opacity: 0.5;
.account__header__image,
.account__avatar {
filter: grayscale(100%);
}
}
&__info {
position: absolute;
top: 10px;
inset-inline-start: 10px;
}
&__image {
overflow: hidden;
height: 145px;
position: relative;
background: darken($ui-base-color, 4%);
img {
object-fit: cover;
display: block;
width: 100%;
height: 100%;
margin: 0;
}
}
&__bar {
position: relative;
background: lighten($ui-base-color, 4%);
padding: 5px;
border-bottom: 1px solid lighten($ui-base-color, 12%);
.avatar {
display: block;
flex: 0 0 auto;
width: 94px;
.account__avatar {
background: darken($ui-base-color, 8%);
border: 2px solid lighten($ui-base-color, 4%);
}
}
}
&__badges {
display: flex;
flex-wrap: wrap;
gap: 8px;
.account-role {
line-height: unset;
}
}
&__tabs {
display: flex;
align-items: flex-start;
justify-content: space-between;
padding: 7px 10px;
margin-top: -55px;
gap: 8px;
overflow: hidden;
margin-inline-start: -2px; // aligns the pfp with content below
&__buttons {
display: flex;
align-items: center;
gap: 8px;
padding-top: 55px;
overflow: hidden;
.button {
flex-shrink: 1;
white-space: nowrap;
@media screen and (max-width: $no-gap-breakpoint) {
min-width: 0;
}
}
.icon-button {
border: 1px solid lighten($ui-base-color, 12%);
border-radius: 4px;
box-sizing: content-box;
padding: 5px;
.icon {
width: 24px;
height: 24px;
}
}
}
&__name {
padding: 5px 10px;
.emojione {
width: 22px;
height: 22px;
}
h1 {
font-size: 16px;
line-height: 24px;
color: $primary-text-color;
font-weight: 500;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
small {
display: block;
font-size: 14px;
color: $darker-text-color;
font-weight: 400;
overflow: hidden;
text-overflow: ellipsis;
span {
user-select: all;
}
.icon-lock {
height: 16px;
width: 16px;
position: relative;
top: 3px;
}
}
}
}
.spacer {
flex: 1 1 auto;
}
}
&__bio {
overflow: hidden;
margin: 0 -5px;
.account__header__content {
padding: 20px 15px;
padding-bottom: 5px;
color: $primary-text-color;
}
.account__header__joined {
font-size: 14px;
padding: 5px 15px;
color: $darker-text-color;
.columns-area--mobile & {
padding-inline-start: 20px;
padding-inline-end: 20px;
}
}
.account__header__fields {
margin: 0;
border-top: 1px solid lighten($ui-base-color, 12%);
a {
color: lighten($ui-highlight-color, 8%);
}
dl:first-child .verified {
border-radius: 0 4px 0 0;
}
.icon {
width: 18px;
height: 18px;
vertical-align: middle;
}
dd {
display: flex;
align-items: center;
gap: 4px;
}
.verified a {
color: $valid-value-color;
}
}
}
&__extra {
margin-top: 4px;
&__links {
font-size: 14px;
color: $darker-text-color;
padding: 10px 0;
a {
display: inline-block;
color: $darker-text-color;
text-decoration: none;
padding: 5px 10px;
font-weight: 500;
strong {
font-weight: 700;
color: $primary-text-color;
}
}
}
}
&__account-note {
margin: 0 -5px;
padding: 10px 15px;
display: flex;
flex-direction: column;
font-size: 14px;
font-weight: 400;
border-top: 1px solid lighten($ui-base-color, 12%);
border-bottom: 1px solid lighten($ui-base-color, 12%);
label {
display: block;
font-size: 12px;
font-weight: 500;
color: $darker-text-color;
text-transform: uppercase;
margin-bottom: 5px;
}
&__content {
white-space: pre-wrap;
padding: 10px 0;
}
strong {
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
}
textarea {
display: block;
box-sizing: border-box;
width: calc(100% + 20px);
color: $secondary-text-color;
background: $ui-base-color;
padding: 10px;
margin: 0 -10px;
font-family: inherit;
font-size: 14px;
resize: none;
border: 0;
outline: 0;
border-radius: 4px;
&::placeholder {
color: $dark-text-color;
opacity: 1;
}
}
}
}
.account__contents {
overflow: hidden;
}
.account__details {
display: flex;
flex-wrap: wrap;
column-gap: 1em;
}
.verified-badge {
display: inline-flex;
align-items: center;
color: $valid-value-color;
gap: 4px;
overflow: hidden;
white-space: nowrap;
> span {
overflow: hidden;
text-overflow: ellipsis;
}
a {
color: inherit;
font-weight: 500;
text-decoration: none;
}
.icon {
width: 16px;
height: 16px;
}
}
.moved-account-banner,
.follow-request-banner,
.account-memorial-banner {
padding: 20px;
background: lighten($ui-base-color, 4%);
display: flex;
align-items: center;
flex-direction: column;
&__message {
color: $darker-text-color;
padding: 8px 0;
padding-top: 0;
padding-bottom: 4px;
font-size: 14px;
font-weight: 500;
text-align: center;
margin-bottom: 16px;
}
&__action {
display: flex;
justify-content: space-between;
align-items: center;
gap: 15px;
width: 100%;
}
.detailed-status__display-name {
margin-bottom: 0;
}
}
.follow-request-banner .button {
width: 100%;
}
.account-memorial-banner__message {
margin-bottom: 0;
}

View File

@ -1,233 +0,0 @@
.announcements__item__content {
word-wrap: break-word;
overflow-y: auto;
.emojione {
width: 20px;
height: 20px;
margin: -3px 0 0;
}
p {
margin-bottom: 10px;
white-space: pre-wrap;
&:last-child {
margin-bottom: 0;
}
}
a {
color: $secondary-text-color;
text-decoration: none;
&:hover {
text-decoration: underline;
}
&.mention {
&:hover {
text-decoration: none;
span {
text-decoration: underline;
}
}
}
&.unhandled-link {
color: $highlight-text-color;
}
}
}
.announcements {
background: lighten($ui-base-color, 8%);
font-size: 13px;
display: flex;
align-items: flex-end;
&__mastodon {
width: 124px;
flex: 0 0 auto;
@media screen and (max-width: 124px + 300px) {
display: none;
}
}
&__container {
width: calc(100% - 124px);
flex: 0 0 auto;
position: relative;
@media screen and (max-width: 124px + 300px) {
width: 100%;
}
}
&__item {
box-sizing: border-box;
width: 100%;
padding: 15px;
position: relative;
font-size: 15px;
line-height: 20px;
word-wrap: break-word;
font-weight: 400;
max-height: 50vh;
overflow: hidden;
display: flex;
flex-direction: column;
&__range {
display: block;
font-weight: 500;
margin-bottom: 10px;
padding-inline-end: 18px;
}
&__unread {
position: absolute;
top: 19px;
inset-inline-end: 19px;
display: block;
background: $highlight-text-color;
border-radius: 50%;
width: 0.625rem;
height: 0.625rem;
}
}
&__pagination {
padding: 15px;
color: $darker-text-color;
position: absolute;
bottom: 3px;
inset-inline-end: 0;
}
}
.layout-multiple-columns .announcements__mastodon {
display: none;
}
.layout-multiple-columns .announcements__container {
width: 100%;
}
.reactions-bar {
display: flex;
flex-wrap: wrap;
align-items: center;
margin-top: 15px;
margin-inline-start: -2px;
width: calc(100% - (90px - 33px));
&__item {
flex-shrink: 0;
background: lighten($ui-base-color, 12%);
border: 0;
border-radius: 3px;
margin: 2px;
cursor: pointer;
user-select: none;
padding: 0 6px;
display: flex;
align-items: center;
transition: all 100ms ease-in;
transition-property: background-color, color;
&__emoji {
display: block;
margin: 3px 0;
width: 16px;
height: 16px;
img {
display: block;
margin: 0;
width: 100%;
height: 100%;
min-width: auto;
min-height: auto;
vertical-align: bottom;
object-fit: contain;
}
}
&__count {
display: block;
min-width: 9px;
font-size: 13px;
font-weight: 500;
text-align: center;
margin-inline-start: 6px;
color: $darker-text-color;
}
&:hover,
&:focus,
&:active {
background: lighten($ui-base-color, 16%);
transition: all 200ms ease-out;
transition-property: background-color, color;
&__count {
color: lighten($darker-text-color, 4%);
}
}
&.active {
transition: all 100ms ease-in;
transition-property: background-color, color;
background-color: mix(
lighten($ui-base-color, 12%),
$ui-highlight-color,
80%
);
.reactions-bar__item__count {
color: lighten($highlight-text-color, 8%);
}
}
}
.emoji-picker-dropdown {
margin: 2px;
}
&:hover .emoji-button {
opacity: 0.85;
}
.emoji-button {
color: $darker-text-color;
margin: 0;
font-size: 16px;
width: auto;
flex-shrink: 0;
padding: 0 6px;
height: 22px;
display: flex;
align-items: center;
opacity: 0.5;
transition: all 100ms ease-in;
transition-property: background-color, color;
&:hover,
&:active,
&:focus {
opacity: 1;
color: lighten($darker-text-color, 4%);
transition: all 200ms ease-out;
transition-property: background-color, color;
}
}
&--empty {
.emoji-button {
padding: 0;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,668 +0,0 @@
.compose-form {
padding: 10px;
.emoji-picker-dropdown {
position: absolute;
top: 0;
inset-inline-end: 0;
::-webkit-scrollbar-track:hover,
::-webkit-scrollbar-track:active {
background-color: rgba($base-overlay-background, 0.3);
}
}
}
.character-counter {
cursor: default;
font-family: $font-sans-serif, sans-serif;
font-size: 14px;
font-weight: 600;
color: $lighter-text-color;
&.character-counter--over {
color: $warning-red;
}
}
.no-reduce-motion .spoiler-input {
transition:
height 0.4s ease,
opacity 0.4s ease;
}
.spoiler-input {
height: 0;
transform-origin: bottom;
opacity: 0;
&.spoiler-input--visible {
height: 36px;
margin-bottom: 11px;
opacity: 1;
}
input {
display: block;
box-sizing: border-box;
margin: 0;
border: 0;
border-radius: 4px;
padding: 10px;
width: 100%;
outline: 0;
color: $inverted-text-color;
background: $simple-background-color;
font-size: 14px;
font-family: inherit;
resize: vertical;
&::placeholder {
color: $dark-text-color;
}
&:focus {
outline: 0;
}
@include single-column('screen and (max-width: 630px)') {
font-size: 16px;
}
}
}
.compose-form__warning {
color: $inverted-text-color;
margin-bottom: 15px;
background: $ui-primary-color;
box-shadow: 0 2px 6px rgba($base-shadow-color, 0.3);
padding: 8px 10px;
border-radius: 4px;
font-size: 13px;
font-weight: 400;
a {
color: $lighter-text-color;
font-weight: 500;
text-decoration: underline;
&:active,
&:focus,
&:hover {
text-decoration: none;
}
}
}
.compose-form__sensitive-button {
padding: 10px;
padding-top: 0;
font-size: 14px;
font-weight: 500;
&.active {
color: $highlight-text-color;
}
input[type='checkbox'] {
appearance: none;
display: inline-block;
position: relative;
border: 1px solid $ui-primary-color;
box-sizing: border-box;
width: 18px;
height: 18px;
flex: 0 0 auto;
margin-inline-start: 5px;
margin-inline-end: 10px;
top: -1px;
border-radius: 4px;
vertical-align: middle;
cursor: inherit;
&:checked {
border-color: $highlight-text-color;
background: $highlight-text-color
url("data:image/svg+xml;utf8,<svg width='18' height='18' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M4.5 8.5L8 12l6-6' stroke='white' stroke-width='1.5'/></svg>")
center center no-repeat;
}
}
}
.reply-indicator {
margin: 0 0 10px;
border-radius: 4px;
padding: 10px;
background: $ui-primary-color;
min-height: 23px;
overflow-y: auto;
flex: 0 2 auto;
}
.reply-indicator__header {
margin-bottom: 5px;
overflow: hidden;
}
.reply-indicator__cancel {
float: right;
line-height: 24px;
}
.reply-indicator__display-name {
color: $inverted-text-color;
display: block;
max-width: 100%;
line-height: 24px;
overflow: hidden;
text-decoration: none;
& > .display-name {
line-height: unset;
height: unset;
}
}
.reply-indicator__display-avatar {
float: left;
margin-inline-end: 5px;
}
.reply-indicator__content {
position: relative;
font-size: 14px;
line-height: 20px;
word-wrap: break-word;
font-weight: 400;
overflow: hidden;
padding-top: 5px;
color: $inverted-text-color;
white-space: pre-wrap;
p,
pre {
margin-bottom: 20px;
white-space: pre-wrap;
&:last-child {
margin-bottom: 0;
}
}
a {
color: $lighter-text-color;
text-decoration: none;
&:hover {
text-decoration: underline;
}
&.mention {
&:hover {
text-decoration: none;
span {
text-decoration: underline;
}
}
}
}
.emojione {
width: 20px;
height: 20px;
margin: -5px 0 0;
}
}
.compose-form .compose-form__autosuggest-wrapper {
position: relative;
}
.compose-form .autosuggest-textarea,
.compose-form .autosuggest-input {
position: relative;
width: 100%;
label {
.autosuggest-textarea__textarea {
display: block;
box-sizing: border-box;
margin: 0;
border: 0;
border-radius: 4px 4px 0 0;
padding: 10px 32px 0 10px;
width: 100%;
min-height: 100px;
outline: 0;
color: $inverted-text-color;
background: $simple-background-color;
font-size: 14px;
font-family: inherit;
resize: none;
scrollbar-color: initial;
&::placeholder {
color: $dark-text-color;
}
&::-webkit-scrollbar {
all: unset;
}
&:focus {
outline: 0;
}
@include single-column('screen and (max-width: 630px)') {
font-size: 16px;
}
@include limited-single-column('screen and (max-width: 600px)') {
height: 100px !important; // prevent auto-resize textarea
resize: vertical;
}
}
}
}
.compose-form__textarea-icons {
display: block;
position: absolute;
top: 29px;
inset-inline-end: 5px;
bottom: 5px;
overflow: hidden;
& > .textarea_icon {
display: block;
margin-top: 2px;
margin-inline-start: 2px;
width: 24px;
height: 24px;
color: $lighter-text-color;
font-size: 18px;
line-height: 24px;
text-align: center;
opacity: 0.8;
}
}
.autosuggest-textarea__suggestions-wrapper {
position: relative;
height: 0;
}
.autosuggest-textarea__suggestions {
box-sizing: border-box;
display: none;
position: absolute;
top: 100%;
width: 100%;
z-index: 99;
box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);
background: $ui-secondary-color;
border-radius: 0 0 4px 4px;
color: $inverted-text-color;
font-size: 14px;
padding: 6px;
}
.autosuggest-textarea__suggestions--visible {
display: block;
}
.autosuggest-textarea__suggestions__item {
padding: 10px;
cursor: pointer;
border-radius: 4px;
&:hover,
&:focus,
&:active,
&.selected {
background: darken($ui-secondary-color, 10%);
}
.autosuggest-account,
.autosuggest-emoji,
.autosuggest-hashtag {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
line-height: 18px;
font-size: 14px;
}
.autosuggest-hashtag {
justify-content: space-between;
&__name {
flex: 1 1 auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
strong {
font-weight: 500;
}
&__uses {
flex: 0 0 auto;
text-align: end;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.autosuggest-account-icon,
.autosuggest-emoji img {
margin-inline-end: 8px;
}
.autosuggest-account .display-name > span {
color: $lighter-text-color;
}
}
.compose-form__upload-wrapper {
overflow: hidden;
}
.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%;
.compose-form__upload-thumbnail {
position: relative;
border-radius: 4px;
height: 140px;
width: 100%;
background-color: $base-shadow-color;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
overflow: hidden;
& > .close {
mix-blend-mode: difference;
}
}
.icon-button {
flex: 0 1 auto;
color: $secondary-text-color;
font-size: 14px;
font-weight: 500;
padding: 10px;
font-family: inherit;
&:hover,
&:focus,
&:active {
color: lighten($secondary-text-color, 7%);
}
}
&__warning {
position: absolute;
z-index: 2;
bottom: 0;
inset-inline-start: 0;
inset-inline-end: 0;
box-sizing: border-box;
background: linear-gradient(
0deg,
rgba($base-shadow-color, 0.8) 0,
rgba($base-shadow-color, 0.35) 80%,
transparent
);
}
}
.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;
}
.upload-progress {
display: flex;
padding: 10px;
color: $darker-text-color;
overflow: hidden;
gap: 10px;
.icon {
width: 24px;
height: 24px;
}
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: darken($simple-background-color, 8%);
}
.upload-progress__tracker {
position: absolute;
top: 0;
inset-inline-start: 0;
height: 6px;
border-radius: 6px;
background: $ui-highlight-color;
}
.compose-form__modifiers {
color: $inverted-text-color;
font-family: inherit;
font-size: 14px;
background: $simple-background-color;
}
.compose-form__buttons-wrapper {
padding: 10px;
background: darken($simple-background-color, 8%);
border-radius: 0 0 4px 4px;
height: 27px;
display: flex;
justify-content: space-between;
flex: 0 0 auto;
}
.compose-form__buttons {
display: flex;
flex: 0 0 auto;
gap: 2px;
.icon-button {
height: 100%;
}
& .icon-button,
& .text-icon-button {
box-sizing: content-box;
padding: 0 3px;
}
}
.character-counter__wrapper {
align-self: center;
margin-inline-end: 4px;
}
.privacy-dropdown__dropdown {
border-radius: 4px;
box-shadow: var(--dropdown-shadow);
background: $simple-background-color;
overflow: hidden;
transform-origin: 50% 0;
}
.privacy-dropdown__option {
display: flex;
align-items: center;
padding: 10px;
color: $inverted-text-color;
cursor: pointer;
.privacy-dropdown__option__content {
flex: 1 1 auto;
color: $lighter-text-color;
&:not(:first-child) {
margin-inline-start: 10px;
}
strong {
display: block;
color: $inverted-text-color;
font-weight: 500;
}
}
&:hover,
&.active {
background: $ui-highlight-color;
color: $primary-text-color;
.privacy-dropdown__option__content {
color: $primary-text-color;
strong {
color: $primary-text-color;
}
}
}
&.active:hover {
background: lighten($ui-highlight-color, 4%);
}
}
.compose-form__publish {
display: flex;
justify-content: flex-end;
min-width: 0;
flex: 0 0 auto;
column-gap: 5px;
.compose-form__publish-button-wrapper {
padding-top: 10px;
button {
padding: 7px 10px;
text-align: center;
& > span {
display: flex;
gap: 5px;
align-items: center;
}
}
.side_arm {
height: 100%;
}
}
}
.language-dropdown {
&__dropdown {
background: $simple-background-color;
box-shadow: var(--dropdown-shadow);
border-radius: 4px;
overflow: hidden;
z-index: 2;
&.top {
transform-origin: 50% 100%;
}
&.bottom {
transform-origin: 50% 0;
}
.emoji-mart-search {
padding-inline-end: 10px;
}
.emoji-mart-search-icon {
inset-inline-end: 10px + 5px;
}
.emoji-mart-scroll {
padding: 0 10px 10px;
}
&__results {
&__item {
cursor: pointer;
color: $inverted-text-color;
font-weight: 500;
padding: 10px;
border-radius: 4px;
display: flex;
gap: 6px;
align-items: center;
&:focus,
&:active,
&:hover {
background: $ui-secondary-color;
}
&__common-name {
color: $darker-text-color;
}
&.active {
background: $ui-highlight-color;
color: $primary-text-color;
outline: 0;
.language-dropdown__dropdown__results__item__common-name {
color: $secondary-text-color;
}
&:hover {
background: lighten($ui-highlight-color, 4%);
}
}
}
}
}
}

View File

@ -1,68 +0,0 @@
.scrollable .account-card {
margin: 10px;
background: lighten($ui-base-color, 8%);
}
.scrollable .account-card__title__avatar {
img,
.account__avatar {
border-color: lighten($ui-base-color, 8%);
}
}
.scrollable .account-card__bio::after {
background: linear-gradient(
to left,
lighten($ui-base-color, 8%),
transparent
);
}
.filter-form {
background: $ui-base-color;
&__column {
padding: 10px 15px;
padding-bottom: 0;
}
.radio-button {
display: block;
}
}
.radio-button {
font-size: 14px;
position: relative;
display: inline-block;
padding: 6px 0;
line-height: 18px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
input[type='radio'],
input[type='checkbox'] {
display: none;
}
&__input {
display: inline-block;
position: relative;
border: 1px solid $ui-primary-color;
box-sizing: border-box;
width: 18px;
height: 18px;
flex: 0 0 auto;
margin-inline-end: 10px;
top: -1px;
border-radius: 50%;
vertical-align: middle;
&.checked {
border-color: lighten($ui-highlight-color, 4%);
background: lighten($ui-highlight-color, 4%);
}
}
}

View File

@ -1,23 +0,0 @@
.domain {
padding: 10px;
border-bottom: 1px solid lighten($ui-base-color, 8%);
.domain__domain-name {
flex: 1 1 auto;
display: block;
color: $primary-text-color;
text-decoration: none;
font-size: 14px;
font-weight: 500;
}
}
.domain__wrapper {
display: flex;
}
.domain_buttons {
height: 18px;
padding: 10px;
white-space: nowrap;
}

View File

@ -1,309 +0,0 @@
.drawer {
width: 300px;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow-y: hidden;
padding: 10px 5px;
flex: none;
&:first-child {
padding-inline-start: 10px;
}
&:last-child {
padding-inline-end: 10px;
}
@include single-column('screen and (max-width: 630px)') {
flex: auto;
}
@include limited-single-column('screen and (max-width: 630px)') {
&,
&:first-child,
&:last-child {
padding: 0;
}
}
.wide & {
min-width: 300px;
max-width: 400px;
flex: 1 1 200px;
}
@include single-column('screen and (max-width: 630px)') {
:root & {
// Overrides `.wide` for single-column view
flex: auto;
width: 100%;
min-width: 0;
max-width: none;
padding: 0;
}
}
.react-swipeable-view-container & {
height: 100%;
}
}
.drawer__tab {
display: flex;
flex: 1 1 auto;
padding: 13px 3px 11px;
color: $darker-text-color;
text-decoration: none;
text-align: center;
font-size: 16px;
align-items: center;
justify-content: center;
border-bottom: 2px solid transparent;
}
.drawer__header {
flex: none;
font-size: 16px;
background: $ui-base-color;
margin-bottom: 10px;
display: flex;
flex-direction: row;
border-radius: 4px;
overflow: hidden;
a:hover {
background: lighten($ui-base-color, 3%);
}
}
.search {
position: relative;
margin-bottom: 10px;
flex: none;
@include limited-single-column(
'screen and (max-width: #{$no-gap-breakpoint})'
) {
margin-bottom: 0;
}
@include single-column('screen and (max-width: 630px)') {
font-size: 16px;
}
}
.navigation-bar {
padding: 10px;
color: $darker-text-color;
display: flex;
align-items: center;
a {
color: inherit;
text-decoration: none;
}
.acct {
display: block;
color: $secondary-text-color;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.navigation-bar__actions {
position: relative;
.compose__action-bar .icon-button {
pointer-events: auto;
transform: scale(1, 1) translate(0, 0);
opacity: 1;
.icon {
width: 24px;
height: 24px;
}
}
}
}
.navigation-bar__profile {
display: flex;
flex-direction: column;
flex: 1 1 auto;
margin-inline-start: 8px;
}
.drawer--results {
overflow-x: hidden;
overflow-y: scroll;
}
.search-results__section {
border-bottom: 1px solid lighten($ui-base-color, 8%);
&:last-child {
border-bottom: 0;
}
&__header {
background: darken($ui-base-color, 4%);
border-bottom: 1px solid lighten($ui-base-color, 8%);
padding: 15px;
font-weight: 500;
font-size: 14px;
color: $darker-text-color;
display: flex;
justify-content: space-between;
h3 {
display: flex;
align-items: center;
gap: 5px;
}
button {
color: $highlight-text-color;
padding: 0;
border: 0;
background: 0;
font: inherit;
&:hover,
&:active,
&:focus {
text-decoration: underline;
}
}
}
.account:last-child,
& > div:last-child .status {
border-bottom: 0;
}
& > .hashtag {
display: block;
padding: 10px;
color: $secondary-text-color;
text-decoration: none;
&:hover,
&:active,
&:focus {
color: lighten($secondary-text-color, 4%);
text-decoration: underline;
}
}
}
.drawer__pager {
box-sizing: border-box;
padding: 0;
flex-grow: 1;
position: relative;
overflow: hidden;
display: flex;
border-radius: 4px;
}
.drawer__inner {
position: absolute;
top: 0;
inset-inline-start: 0;
background: $ui-base-color;
box-sizing: border-box;
padding: 0;
display: flex;
flex-direction: column;
overflow: hidden;
overflow-y: auto;
width: 100%;
height: 100%;
&.darker {
background: $ui-base-color;
}
}
.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($ui-base-color)}"/></svg>')
no-repeat bottom / 100% auto;
flex: 1;
min-height: 47px;
display: none;
> img {
display: block;
object-fit: contain;
object-position: bottom left;
width: 85%;
height: 100%;
pointer-events: none;
user-select: none;
}
> .mastodon {
display: block;
width: 100%;
height: 100%;
border: 0;
cursor: inherit;
}
@media screen and (height >= 640px) {
display: block;
}
}
.pseudo-drawer {
background: lighten($ui-base-color, 13%);
font-size: 13px;
text-align: start;
}
.drawer__backdrop {
cursor: pointer;
position: absolute;
top: 0;
inset-inline-start: 0;
width: 100%;
height: 100%;
background: rgba($base-overlay-background, 0.5);
}
@for $i from 0 through 3 {
.mbstobon-#{$i} .drawer__inner__mastodon {
@if $i == 3 {
background:
url('~flavours/glitch/images/wave-drawer.png')
no-repeat
bottom /
100%
auto,
$ui-base-color;
} @else {
background:
url('~flavours/glitch/images/wave-drawer-glitched.png')
no-repeat
bottom /
100%
auto,
$ui-base-color;
}
& > .mastodon {
background: url('~flavours/glitch/images/mbstobon-ui-#{$i}.png')
no-repeat
left
bottom /
contain;
@if $i != 3 {
filter: contrast(50%) brightness(50%);
}
}
}
}

View File

@ -1,106 +0,0 @@
.emojione {
font-size: inherit;
vertical-align: middle;
object-fit: contain;
margin: -0.2ex 0.15em 0.2ex;
width: 16px;
height: 16px;
img {
width: auto;
}
}
.emoji-picker-dropdown__menu {
background: $simple-background-color;
position: relative;
box-shadow: var(--dropdown-shadow);
border-radius: 4px;
margin-top: 5px;
z-index: 2;
.emoji-mart-scroll {
transition: opacity 200ms ease;
}
&.selecting .emoji-mart-scroll {
opacity: 0.5;
}
}
.emoji-picker-dropdown__modifiers {
position: absolute;
top: 60px;
inset-inline-end: 11px;
cursor: pointer;
}
.emoji-picker-dropdown__modifiers__menu {
position: absolute;
z-index: 4;
top: -4px;
inset-inline-start: -8px;
background: $simple-background-color;
border-radius: 4px;
box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
overflow: hidden;
button {
display: block;
cursor: pointer;
border: 0;
padding: 4px 8px;
background: transparent;
&:hover,
&:focus,
&:active {
background: rgba($ui-secondary-color, 0.4);
}
}
.emoji-mart-emoji {
height: 22px;
}
}
.emoji-mart-emoji {
span {
background-repeat: no-repeat;
}
}
.emoji-button {
display: block;
padding-top: 5px;
padding-bottom: 2px;
padding-inline-start: 2px;
padding-inline-end: 5px;
outline: 0;
cursor: pointer;
img {
filter: grayscale(100%);
opacity: 0.8;
display: block;
margin: 0;
width: 22px;
height: 22px;
}
&:hover,
&:active,
&:focus {
img {
opacity: 1;
filter: none;
border-radius: 100%;
}
}
&:focus-visible {
img {
outline: $ui-button-icon-focus-outline;
}
}
}

View File

@ -1,143 +0,0 @@
.account-card__header {
position: relative;
}
.explore__search-header {
background: darken($ui-base-color, 4%);
justify-content: center;
align-items: center;
padding: 15px;
.search {
width: 100%;
margin-bottom: 0;
}
.search__input {
border: 1px solid lighten($ui-base-color, 8%);
padding: 10px;
}
.search__popout {
border: 1px solid lighten($ui-base-color, 8%);
}
.search .icon {
top: 9px;
inset-inline-end: 10px;
color: $dark-text-color;
}
}
.explore__search-results {
flex: 1 1 auto;
display: flex;
flex-direction: column;
background: $ui-base-color;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.story {
display: flex;
align-items: center;
color: $primary-text-color;
text-decoration: none;
padding: 15px;
border-bottom: 1px solid lighten($ui-base-color, 8%);
gap: 15px;
&:last-child {
border-bottom: 0;
}
&:hover,
&:active,
&:focus {
color: $highlight-text-color;
.story__details__publisher,
.story__details__shared {
color: $highlight-text-color;
}
}
&__details {
flex: 1 1 auto;
&__publisher {
color: $darker-text-color;
margin-bottom: 8px;
}
&__title {
font-size: 19px;
line-height: 24px;
font-weight: 500;
margin-bottom: 8px;
}
&__shared {
color: $darker-text-color;
}
strong {
font-weight: 500;
}
}
&__thumbnail {
flex: 0 0 auto;
position: relative;
width: 120px;
height: 120px;
.skeleton {
width: 100%;
height: 100%;
}
img {
border-radius: 8px;
display: block;
margin: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
&__preview {
border-radius: 8px;
display: block;
margin: 0;
width: 100%;
height: 100%;
object-fit: fill;
position: absolute;
top: 0;
inset-inline-start: 0;
z-index: 0;
&--hidden {
display: none;
}
}
}
&.expanded {
flex-direction: column;
.story__thumbnail {
order: 1;
width: 100%;
height: auto;
aspect-ratio: 1.91 / 1;
}
.story__details {
order: 2;
width: 100%;
flex: 0 0 auto;
}
}
}

View File

@ -1,24 +0,0 @@
@import 'misc';
@import 'accounts';
@import 'domains';
@import 'status';
@import 'modal';
@import 'compose_form';
@import 'columns';
@import 'regeneration_indicator';
@import 'directory';
@import 'search';
@import 'emoji';
@import 'doodle';
@import 'drawer';
@import 'media';
@import 'sensitive';
@import 'lists';
@import 'emoji_picker';
@import 'local_settings';
@import 'single_column';
@import 'announcements';
@import 'explore';
@import 'signed_out';
@import 'privacy_policy';
@import 'about';

View File

@ -1,94 +0,0 @@
.list-editor {
background: $ui-base-color;
flex-direction: column;
border-radius: 8px;
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
width: 380px;
overflow: hidden;
@media screen and (width <= 420px) {
width: 90%;
}
h4 {
padding: 15px 0;
background: lighten($ui-base-color, 13%);
font-weight: 500;
font-size: 16px;
text-align: center;
border-radius: 8px 8px 0 0;
}
.drawer__pager {
height: 50vh;
}
.drawer__inner {
border-radius: 0 0 8px 8px;
&.backdrop {
width: calc(100% - 60px);
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
border-radius: 0 0 0 8px;
}
}
&__accounts {
overflow-y: auto;
}
.account__display-name {
&:hover strong {
text-decoration: none;
}
}
.account__avatar {
cursor: default;
}
.search {
margin-bottom: 0;
}
}
.list-adder {
background: $ui-base-color;
flex-direction: column;
border-radius: 8px;
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
width: 380px;
overflow: hidden;
@media screen and (width <= 420px) {
width: 90%;
}
&__account {
background: lighten($ui-base-color, 13%);
}
&__lists {
background: lighten($ui-base-color, 13%);
height: 50vh;
border-radius: 0 0 8px 8px;
overflow-y: auto;
}
.list {
padding: 10px;
border-bottom: 1px solid lighten($ui-base-color, 8%);
}
.list__wrapper {
display: flex;
}
.list__display-name {
flex: 1 1 auto;
overflow: hidden;
text-decoration: none;
font-size: 16px;
padding: 10px;
}
}

View File

@ -1,802 +0,0 @@
.video-error-cover {
align-items: center;
background: $base-overlay-background;
color: $primary-text-color;
cursor: pointer;
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
margin-top: 8px;
position: relative;
text-align: center;
z-index: 100;
}
.media-spoiler {
background: $base-overlay-background;
color: $darker-text-color;
border: 0;
width: 100%;
height: 100%;
&:hover,
&:active,
&:focus {
color: lighten($darker-text-color, 8%);
}
.status__content > & {
margin-top: 15px; // Add margin when used bare for NSFW video player
}
@include fullwidth-gallery;
}
.media-spoiler__warning {
display: block;
font-size: 14px;
}
.media-spoiler__trigger {
display: block;
font-size: 11px;
font-weight: 500;
}
.media-gallery__item__badges {
position: absolute;
bottom: 6px;
inset-inline-start: 6px;
display: flex;
gap: 2px;
}
.media-gallery__alt__label,
.media-gallery__gifv__label {
display: flex;
align-items: center;
justify-content: center;
color: $white;
background: rgba($black, 0.65);
padding: 2px 6px;
border-radius: 4px;
font-size: 11px;
font-weight: 700;
z-index: 1;
pointer-events: none;
line-height: 18px;
.icon {
width: 15px;
height: 15px;
}
}
.media-gallery {
box-sizing: border-box;
margin-top: 8px;
overflow: hidden;
border-radius: 4px;
position: relative;
width: 100%;
min-height: 64px;
display: grid;
grid-template-columns: 50% 50%;
grid-template-rows: 50% 50%;
gap: 2px;
@include fullwidth-gallery;
}
.media-gallery__item {
border: 0;
box-sizing: border-box;
display: block;
position: relative;
border-radius: 4px;
overflow: hidden;
&--tall {
grid-row: span 2;
}
&--wide {
grid-column: span 2;
}
.full-width & {
border-radius: 0;
}
&.letterbox {
background: $base-shadow-color;
}
}
.media-gallery__item-thumbnail {
cursor: zoom-in;
display: block;
text-decoration: none;
color: $secondary-text-color;
position: relative;
z-index: 1;
&,
img {
height: 100%;
width: 100%;
object-fit: contain;
&:not(.letterbox) {
height: 100%;
object-fit: cover;
}
}
}
.media-gallery__preview {
width: 100%;
height: 100%;
object-fit: cover;
position: absolute;
top: 0;
inset-inline-start: 0;
z-index: 0;
background: $base-overlay-background;
&--hidden {
display: none;
}
}
.media-gallery__gifv {
height: 100%;
overflow: hidden;
position: relative;
width: 100%;
display: flex;
justify-content: center;
}
.media-gallery__item-gifv-thumbnail {
cursor: zoom-in;
height: 100%;
width: 100%;
object-fit: contain;
user-select: none;
&:not(.letterbox) {
height: 100%;
object-fit: cover;
}
}
.media-gallery__item-thumbnail-label {
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
overflow: hidden;
position: absolute;
}
.video-modal__container {
max-width: 100vw;
max-height: 100vh;
}
.audio-modal__container {
width: 50vw;
}
.media-modal {
width: 100%;
height: 100%;
position: relative;
&__close,
&__zoom-button {
color: rgba($white, 0.7);
&:hover,
&:focus,
&:active {
color: $white;
background-color: rgba($white, 0.15);
}
&:focus {
background-color: rgba($white, 0.3);
}
}
}
.media-modal__closer {
position: absolute;
top: 0;
inset-inline-start: 0;
inset-inline-end: 0;
bottom: 0;
}
.media-modal__navigation {
position: absolute;
top: 0;
inset-inline-start: 0;
inset-inline-end: 0;
bottom: 0;
pointer-events: none;
transition: opacity 0.3s linear;
will-change: opacity;
* {
pointer-events: auto;
}
&.media-modal__navigation--hidden {
opacity: 0;
* {
pointer-events: none;
}
}
}
.media-modal__nav {
background: transparent;
box-sizing: border-box;
border: 0;
color: rgba($white, 0.7);
cursor: pointer;
display: flex;
align-items: center;
font-size: 24px;
height: 20vmax;
margin: auto 0;
padding: 30px 15px;
position: absolute;
top: 0;
bottom: 0;
&:hover,
&:focus,
&:active {
color: $white;
}
}
.media-modal__nav--left {
inset-inline-start: 0;
}
.media-modal__nav--right {
inset-inline-end: 0;
}
.media-modal__overlay {
max-width: 600px;
position: absolute;
inset-inline-start: 0;
inset-inline-end: 0;
bottom: 0;
margin: 0 auto;
.picture-in-picture__footer {
border-radius: 0;
background: transparent;
padding: 20px 0;
.icon-button {
color: $white;
&:hover,
&:focus,
&:active {
color: $white;
background-color: rgba($white, 0.15);
}
&:focus {
background-color: rgba($white, 0.3);
}
&.active {
color: $highlight-text-color;
&:hover,
&:focus,
&:active {
background: rgba($highlight-text-color, 0.15);
}
&:focus {
background: rgba($highlight-text-color, 0.3);
}
}
&.star-icon.active {
color: $gold-star;
&:hover,
&:focus,
&:active {
background: rgba($gold-star, 0.15);
}
&:focus {
background: rgba($gold-star, 0.3);
}
}
&.disabled {
color: $white;
background-color: transparent;
cursor: default;
opacity: 0.4;
}
}
}
}
.media-modal__pagination {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
.media-modal__page-dot {
flex: 0 0 auto;
background-color: $white;
opacity: 0.4;
height: 6px;
width: 6px;
border-radius: 50%;
margin: 0 4px;
padding: 0;
border: 0;
font-size: 0;
transition: opacity 0.2s ease-in-out;
&.active {
opacity: 1;
}
}
.media-modal__close {
position: absolute;
inset-inline-end: 8px;
top: 8px;
z-index: 100;
}
.detailed,
.fullscreen {
.video-player__volume__current,
.video-player__volume::before {
bottom: 27px;
}
.video-player__volume__handle {
bottom: 23px;
}
}
.audio-player {
overflow: hidden;
box-sizing: border-box;
position: relative;
background: darken($ui-base-color, 8%);
border-radius: 4px;
padding-bottom: 44px;
width: 100%;
&.editable {
border-radius: 0;
height: 100%;
}
&.inactive {
audio,
.video-player__controls {
visibility: hidden;
}
}
.video-player__volume::before,
.video-player__seek::before {
background: currentColor;
opacity: 0.15;
}
.video-player__seek__buffer {
background: currentColor;
opacity: 0.2;
}
.video-player__buttons button,
.video-player__buttons a {
color: currentColor;
opacity: 0.75;
&:active,
&:hover,
&:focus {
color: currentColor;
opacity: 1;
}
}
.video-player__time-sep,
.video-player__time-total,
.video-player__time-current {
color: currentColor;
}
.video-player__seek::before,
.video-player__seek__buffer,
.video-player__seek__progress {
top: 0;
}
.video-player__seek__handle {
top: -4px;
}
.video-player__controls {
padding-top: 10px;
background: transparent;
}
}
.video-player {
overflow: hidden;
position: relative;
background: $base-shadow-color;
max-width: 100%;
border-radius: 4px;
box-sizing: border-box;
color: $white;
display: flex;
align-items: center;
&.editable {
border-radius: 0;
height: 100% !important;
}
&:focus {
outline: 0;
}
.detailed-status & {
width: 100%;
height: 100%;
}
@include fullwidth-gallery;
video {
display: block;
max-width: 100vw;
max-height: 80vh;
z-index: 1;
position: relative;
}
&.fullscreen {
width: 100% !important;
height: 100% !important;
margin: 0;
video {
max-width: 100% !important;
max-height: 100% !important;
width: 100% !important;
height: 100% !important;
outline: 0;
}
}
&.inline {
video {
object-fit: contain;
}
}
&__controls {
position: absolute;
direction: ltr;
z-index: 2;
bottom: 0;
inset-inline-start: 0;
inset-inline-end: 0;
box-sizing: border-box;
background: linear-gradient(
0deg,
rgba($base-shadow-color, 0.85) 0,
rgba($base-shadow-color, 0.45) 60%,
transparent
);
padding: 0 15px;
opacity: 0;
transition: opacity 0.1s ease;
&.active {
opacity: 1;
}
}
&.inactive {
video,
.video-player__controls {
visibility: hidden;
}
}
&__spoiler {
display: none;
position: absolute;
top: 0;
inset-inline-start: 0;
width: 100%;
height: 100%;
z-index: 4;
border: 0;
background: $base-shadow-color;
color: $darker-text-color;
transition: none;
pointer-events: none;
&.active {
display: block;
pointer-events: auto;
&:hover,
&:active,
&:focus {
color: lighten($darker-text-color, 7%);
}
}
&__title {
display: block;
font-size: 14px;
}
&__subtitle {
display: block;
font-size: 11px;
font-weight: 500;
}
}
&__buttons-bar {
display: flex;
justify-content: space-between;
padding-bottom: 8px;
margin: 0 -5px;
.video-player__download__icon {
color: inherit;
.fa,
&:active .fa,
&:hover .fa,
&:focus .fa {
color: inherit;
}
}
}
&__buttons {
display: flex;
flex: 0 1 auto;
min-width: 30px;
align-items: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
gap: 5px;
.player-button {
display: inline-block;
outline: 0;
padding: 5px;
flex: 0 0 auto;
background: transparent;
border: 0;
color: rgba($white, 0.75);
&:active,
&:hover,
&:focus {
color: $white;
}
}
}
&__time {
display: inline;
flex: 0 1 auto;
overflow: hidden;
text-overflow: ellipsis;
margin: 0 5px;
}
&__time-sep,
&__time-total,
&__time-current {
font-size: 14px;
font-weight: 500;
}
&__time-current {
color: $white;
}
&__time-sep {
display: inline-block;
margin: 0 6px;
}
&__time-sep,
&__time-total {
color: $white;
}
&__volume {
flex: 0 0 auto;
display: inline-flex;
cursor: pointer;
height: 24px;
position: relative;
overflow: hidden;
.no-reduce-motion & {
transition: all 100ms linear;
}
&.active {
overflow: visible;
width: 50px;
margin-inline-end: 16px;
}
&::before {
content: '';
width: 50px;
background: rgba($white, 0.35);
border-radius: 4px;
display: block;
position: absolute;
height: 4px;
inset-inline-start: 0;
top: 50%;
transform: translate(0, -50%);
}
&__current {
display: block;
position: absolute;
height: 4px;
border-radius: 4px;
inset-inline-start: 0;
top: 50%;
transform: translate(0, -50%);
background: lighten($ui-highlight-color, 8%);
}
&__handle {
position: absolute;
z-index: 3;
border-radius: 50%;
width: 12px;
height: 12px;
top: 50%;
inset-inline-start: 0;
margin-inline-start: -6px;
transform: translate(0, -50%);
background: lighten($ui-highlight-color, 8%);
box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
opacity: 0;
.no-reduce-motion & {
transition: opacity 100ms linear;
}
}
&.active &__handle {
opacity: 1;
}
}
&__link {
padding: 2px 10px;
a {
text-decoration: none;
font-size: 14px;
font-weight: 500;
color: $white;
&:hover,
&:active,
&:focus {
text-decoration: underline;
}
}
}
&__seek {
cursor: pointer;
height: 24px;
position: relative;
&::before {
content: '';
width: 100%;
background: rgba($white, 0.35);
border-radius: 4px;
display: block;
position: absolute;
height: 4px;
top: 14px;
}
&__progress,
&__buffer {
display: block;
position: absolute;
height: 4px;
border-radius: 4px;
top: 14px;
background: lighten($ui-highlight-color, 8%);
}
&__buffer {
background: rgba($white, 0.2);
}
&__handle {
position: absolute;
z-index: 3;
opacity: 0;
border-radius: 50%;
width: 12px;
height: 12px;
top: 10px;
margin-inline-start: -6px;
background: lighten($ui-highlight-color, 8%);
box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
.no-reduce-motion & {
transition: opacity 0.1s ease;
}
&.active {
opacity: 1;
}
}
&:hover {
.video-player__seek__handle {
opacity: 1;
}
}
}
&.detailed,
&.fullscreen {
.video-player__buttons {
.player-button {
padding-top: 10px;
padding-bottom: 10px;
}
}
}
}
.gifv {
video {
max-width: 100vw;
max-height: 80vh;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,209 +0,0 @@
.privacy-policy {
background: $ui-base-color;
padding: 20px;
@media screen and (min-width: $no-gap-breakpoint) {
border-radius: 4px;
}
&__body {
margin-top: 20px;
}
}
.prose {
color: $secondary-text-color;
font-size: 15px;
line-height: 22px;
p,
ul,
ol {
margin-top: 1.25em;
margin-bottom: 1.25em;
}
img {
margin-top: 2em;
margin-bottom: 2em;
max-width: 100%;
}
video {
margin-top: 2em;
margin-bottom: 2em;
max-width: 100%;
}
figure {
margin-top: 2em;
margin-bottom: 2em;
figcaption {
font-size: 0.875em;
line-height: 1.4285714;
margin-top: 0.8571429em;
}
}
figure > * {
margin-top: 0;
margin-bottom: 0;
}
h1 {
font-size: 1.5em;
margin-top: 0;
margin-bottom: 1em;
line-height: 1.33;
}
h2 {
font-size: 1.25em;
margin-top: 1.6em;
margin-bottom: 0.6em;
line-height: 1.6;
}
h3,
h4,
h5,
h6 {
margin-top: 1.5em;
margin-bottom: 0.5em;
line-height: 1.5;
}
ol {
counter-reset: list-counter;
}
li {
margin-top: 0.5em;
margin-bottom: 0.5em;
}
ol > li {
counter-increment: list-counter;
&::before {
content: counter(list-counter) '.';
position: absolute;
inset-inline-start: 0;
}
}
ul > li::before {
content: '';
position: absolute;
background-color: $darker-text-color;
border-radius: 50%;
width: 0.375em;
height: 0.375em;
top: 0.5em;
inset-inline-start: 0.25em;
}
ul > li,
ol > li {
position: relative;
padding-inline-start: 1.75em;
}
& > ul > li p {
margin-top: 0.75em;
margin-bottom: 0.75em;
}
& > ul > li > *:first-child {
margin-top: 1.25em;
}
& > ul > li > *:last-child {
margin-bottom: 1.25em;
}
& > ol > li > *:first-child {
margin-top: 1.25em;
}
& > ol > li > *:last-child {
margin-bottom: 1.25em;
}
ul ul,
ul ol,
ol ul,
ol ol {
margin-top: 0.75em;
margin-bottom: 0.75em;
}
h1,
h2,
h3,
h4,
h5,
h6,
strong,
b {
color: $primary-text-color;
font-weight: 700;
}
em,
i {
font-style: italic;
}
a {
color: $highlight-text-color;
text-decoration: underline;
&:focus,
&:hover,
&:active {
text-decoration: none;
}
}
code {
font-size: 0.875em;
background: darken($ui-base-color, 8%);
border-radius: 4px;
padding: 0.2em 0.3em;
}
hr {
border: 0;
border-top: 1px solid lighten($ui-base-color, 4%);
margin-top: 3em;
margin-bottom: 3em;
}
hr + * {
margin-top: 0;
}
h2 + * {
margin-top: 0;
}
h3 + * {
margin-top: 0;
}
h4 + *,
h5 + *,
h6 + * {
margin-top: 0;
}
& > :first-child {
margin-top: 0;
}
& > :last-child {
margin-bottom: 0;
}
}

View File

@ -1,43 +0,0 @@
.regeneration-indicator {
text-align: center;
font-size: 16px;
font-weight: 500;
color: $dark-text-color;
background: $ui-base-color;
cursor: default;
display: flex;
flex: 1 1 auto;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
&__figure {
&,
img {
display: block;
width: auto;
height: 160px;
margin: 0;
}
}
&--without-header {
padding-top: 20px + 48px;
}
&__label {
margin-top: 30px;
strong {
display: block;
margin-bottom: 10px;
color: $dark-text-color;
}
span {
font-size: 15px;
font-weight: 400;
}
}
}

View File

@ -1,329 +0,0 @@
.search {
margin-bottom: 10px;
position: relative;
&__popout {
box-sizing: border-box;
display: none;
position: absolute;
inset-inline-start: 0;
margin-top: -2px;
width: 100%;
background: $ui-base-color;
border-radius: 0 0 4px 4px;
box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);
z-index: 99;
font-size: 13px;
padding: 15px 5px;
h4 {
text-transform: uppercase;
color: $dark-text-color;
font-weight: 500;
padding: 0 10px;
margin-bottom: 10px;
}
.icon-button {
padding: 0;
}
.icon {
width: 18px;
height: 18px;
}
&__menu {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
&__message {
color: $dark-text-color;
padding: 0 10px;
}
&__item {
display: block;
box-sizing: border-box;
width: 100%;
border: 0;
font: inherit;
background: transparent;
color: $darker-text-color;
padding: 10px;
cursor: pointer;
border-radius: 4px;
text-align: start;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
&--flex {
display: flex;
justify-content: space-between;
}
.icon-button {
transition: none;
}
&:hover,
&:focus,
&:active,
&.selected {
background: $ui-highlight-color;
color: $primary-text-color;
.icon-button {
color: $primary-text-color;
}
}
mark {
background: transparent;
font-weight: 700;
color: $primary-text-color;
}
span {
overflow: inherit;
text-overflow: inherit;
}
}
}
}
&.active {
.search__popout {
display: block;
}
}
}
.search__input {
@include search-input;
display: block;
padding: 15px;
padding-inline-end: 30px;
line-height: 18px;
font-size: 16px;
&::placeholder {
color: lighten($darker-text-color, 4%);
}
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus,
&:active {
outline: 0 !important;
}
&:focus {
background: lighten($ui-base-color, 4%);
}
}
.search__icon {
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus {
outline: 0 !important;
}
.icon {
position: absolute;
top: 13px;
inset-inline-end: 10px;
display: inline-block;
opacity: 0;
transition: all 100ms linear;
transition-property: color, transform, opacity;
font-size: 18px;
width: 24px;
height: 24px;
color: $secondary-text-color;
cursor: default;
pointer-events: none;
&.active {
pointer-events: auto;
opacity: 0.3;
}
}
.icon-search {
transform: rotate(0deg);
&.active {
pointer-events: auto;
opacity: 0.3;
}
}
.icon-times-circle {
top: 17px;
transform: rotate(0deg);
color: $action-button-color;
cursor: pointer;
&.active {
transform: rotate(90deg);
opacity: 1;
}
&:hover {
color: lighten($action-button-color, 7%);
}
}
}
.search-results__header {
color: $dark-text-color;
background: lighten($ui-base-color, 2%);
padding: 15px;
font-weight: 500;
font-size: 16px;
cursor: default;
display: flex;
align-items: center;
gap: 5px;
}
.search-results__info {
padding: 20px;
color: $darker-text-color;
text-align: center;
}
.trends {
&__item {
display: flex;
align-items: center;
padding: 15px;
border-bottom: 1px solid lighten($ui-base-color, 8%);
gap: 15px;
&:last-child {
border-bottom: 0;
}
&__name {
flex: 1 1 auto;
color: $dark-text-color;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
strong {
font-weight: 500;
}
a {
color: $darker-text-color;
text-decoration: none;
font-size: 14px;
font-weight: 500;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&:hover,
&:focus,
&:active {
span {
text-decoration: underline;
}
}
}
}
&__current {
flex: 0 0 auto;
font-size: 24px;
font-weight: 500;
text-align: end;
color: $secondary-text-color;
text-decoration: none;
}
&__sparkline {
flex: 0 0 auto;
width: 50px;
path:first-child {
fill: rgba($highlight-text-color, 0.25) !important;
fill-opacity: 1 !important;
}
path:last-child {
stroke: lighten($highlight-text-color, 6%) !important;
fill: none !important;
}
}
&--requires-review {
.trends__item__name {
color: $gold-star;
a {
color: $gold-star;
}
}
.trends__item__current {
color: $gold-star;
}
.trends__item__sparkline {
path:first-child {
fill: rgba($gold-star, 0.25) !important;
}
path:last-child {
stroke: lighten($gold-star, 6%) !important;
}
}
}
&--disabled {
.trends__item__name {
color: lighten($ui-base-color, 12%);
a {
color: lighten($ui-base-color, 12%);
}
}
.trends__item__current {
color: lighten($ui-base-color, 12%);
}
.trends__item__sparkline {
path:first-child {
fill: rgba(lighten($ui-base-color, 12%), 0.25) !important;
}
path:last-child {
stroke: lighten(lighten($ui-base-color, 12%), 6%) !important;
}
}
}
}
&--compact &__item {
padding: 10px;
padding-inline-end: 28px;
}
}

View File

@ -1,26 +0,0 @@
.sensitive-info {
display: flex;
flex-direction: row;
align-items: center;
position: absolute;
top: 4px;
inset-inline-start: 4px;
z-index: 100;
}
.sensitive-marker {
margin: 0 3px;
border-radius: 2px;
padding: 2px 6px;
color: rgba($primary-text-color, 0.8);
background: rgba($base-overlay-background, 0.5);
font-size: 12px;
line-height: 18px;
text-transform: uppercase;
opacity: 0.9;
transition: opacity 0.1s ease;
.media-gallery:hover & {
opacity: 1;
}
}

View File

@ -1,106 +0,0 @@
.sign-in-banner {
padding: 10px;
p {
color: $darker-text-color;
margin-bottom: 20px;
a {
color: $secondary-text-color;
text-decoration: none;
unicode-bidi: isolate;
&:hover {
text-decoration: underline;
}
}
}
.button {
margin-bottom: 10px;
}
}
.server-banner {
padding: 20px 0;
&__introduction {
color: $darker-text-color;
margin-bottom: 20px;
strong {
font-weight: 600;
}
a {
color: inherit;
text-decoration: underline;
&:hover,
&:active,
&:focus {
text-decoration: none;
}
}
}
&__hero {
display: block;
border-radius: 4px;
width: 100%;
height: auto;
margin-bottom: 20px;
aspect-ratio: 1.9;
border: 0;
background: $ui-base-color;
object-fit: cover;
}
&__description {
margin-bottom: 20px;
}
&__meta {
display: flex;
gap: 10px;
max-width: 100%;
&__column {
flex: 0 0 auto;
width: calc(50% - 5px);
overflow: hidden;
}
}
&__number {
font-weight: 600;
color: $primary-text-color;
font-size: 14px;
}
&__number-label {
color: $darker-text-color;
font-weight: 500;
font-size: 14px;
}
h4 {
text-transform: uppercase;
color: $darker-text-color;
margin-bottom: 10px;
font-weight: 600;
}
.account {
padding: 0;
border: 0;
}
.account__avatar-wrapper {
margin-inline-start: 0;
}
.spacer {
margin: 10px 0;
}
}

View File

@ -1,319 +0,0 @@
.compose-panel {
width: 285px;
margin-top: 10px;
display: flex;
flex-direction: column;
height: calc(100% - 10px);
overflow-y: hidden;
.hero-widget {
box-shadow: none;
&__text,
&__img,
&__img img {
border-radius: 0;
}
&__text {
padding: 15px;
color: $secondary-text-color;
strong {
font-weight: 700;
color: $primary-text-color;
}
}
}
.search__input {
line-height: 18px;
font-size: 16px;
padding: 15px;
padding-inline-end: 30px;
}
.search__icon .fa {
top: 15px;
}
.navigation-bar {
flex: 0 1 48px;
}
.compose-form {
flex: 1;
display: flex;
flex-direction: column;
min-height: 310px;
}
.compose-form__autosuggest-wrapper {
overflow-y: auto;
background-color: $white;
border-radius: 4px 4px 0 0;
flex: 0 1 auto;
}
.autosuggest-textarea__textarea {
overflow-y: hidden;
}
}
.navigation-panel {
margin-top: 10px;
margin-bottom: 10px;
height: calc(100% - 20px);
overflow-y: auto;
display: flex;
flex-direction: column;
& > a {
flex: 0 0 auto;
}
.logo {
height: 30px;
width: auto;
}
}
.navigation-panel,
.compose-panel {
hr {
flex: 0 0 auto;
border: 0;
background: transparent;
border-top: 1px solid lighten($ui-base-color, 4%);
margin: 10px 0;
}
.flex-spacer {
background: transparent;
}
}
.columns-area--mobile {
flex-direction: column;
width: 100%;
margin: 0 auto;
.column,
.drawer {
width: 100%;
height: 100%;
padding: 0;
}
.account-card {
margin-bottom: 0;
}
.filter-form {
display: flex;
flex-wrap: wrap;
}
.autosuggest-textarea__textarea {
font-size: 16px;
}
.search__input {
line-height: 18px;
font-size: 16px;
padding: 15px;
padding-inline-end: 30px;
}
.search__icon .fa {
top: 15px;
}
.scrollable {
overflow: visible;
@supports (display: grid) {
contain: content;
}
}
@media screen and (min-width: $no-gap-breakpoint) {
padding: 10px 0;
padding-top: 0;
}
.detailed-status {
padding: 15px;
.media-gallery,
.video-player,
.audio-player {
margin-top: 15px;
}
}
.account__header__bar {
padding: 5px 10px;
}
.navigation-bar,
.compose-form {
padding: 15px;
}
.compose-form .compose-form__publish .compose-form__publish-button-wrapper {
padding-top: 15px;
}
.notification__report {
padding: 15px;
padding-inline-start: (48px + 15px * 2);
min-height: 48px + 2px;
&__avatar {
inset-inline-start: 15px;
top: 17px;
}
}
.status {
padding: 15px;
min-height: 48px + 2px;
.media-gallery,
&__action-bar,
.video-player,
.audio-player {
margin-top: 10px;
}
}
.account {
padding: 15px 10px;
&__header__bio {
margin: 0 -10px;
}
}
.notification {
&__message {
padding-top: 15px;
}
.status {
padding-top: 8px;
}
.account {
padding-top: 8px;
}
}
}
@media screen and (min-width: $no-gap-breakpoint) {
.react-swipeable-view-container .columns-area--mobile {
height: calc(100% - 10px) !important;
}
.getting-started__wrapper {
margin-bottom: 10px;
}
.search-page .search {
display: none;
}
.navigation-panel__legal {
display: none;
}
}
@media screen and (max-width: $no-gap-breakpoint - 1px) {
$sidebar-width: 285px;
.columns-area__panels__main {
width: calc(100% - $sidebar-width);
}
.columns-area__panels {
min-height: calc(100vh - $ui-header-height);
}
.columns-area__panels__pane--navigational {
min-width: $sidebar-width;
.columns-area__panels__pane__inner {
width: $sidebar-width;
}
.navigation-panel {
margin: 0;
background: $ui-base-color;
border-inline-start: 1px solid lighten($ui-base-color, 8%);
height: 100vh;
}
.navigation-panel__sign-in-banner,
.navigation-panel__logo,
.navigation-panel__banner,
.getting-started__trends {
display: none;
}
.column-link__icon {
font-size: 18px;
}
}
.layout-single-column .ui__header {
display: flex;
background: $ui-base-color;
border-bottom: 1px solid lighten($ui-base-color, 8%);
}
.column-header,
.column-back-button,
.scrollable,
.error-column {
border-radius: 0 !important;
}
}
@media screen and (max-width: $no-gap-breakpoint - 285px - 1px) {
$sidebar-width: 55px;
.columns-area__panels__main {
width: calc(100% - $sidebar-width);
}
.columns-area__panels__pane--navigational {
min-width: $sidebar-width;
.columns-area__panels__pane__inner {
width: $sidebar-width;
}
.column-link span {
display: none;
}
.list-panel {
display: none;
}
}
}
.explore__search-header {
display: none;
}
@media screen and (max-width: $no-gap-breakpoint - 1px) {
.columns-area__panels__pane--compositional {
display: none;
}
.explore__search-header {
display: flex;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,14 @@
.emoji-mart {
font-size: 13px;
display: inline-block;
color: $inverted-text-color;
&,
* {
box-sizing: border-box;
line-height: 1.15;
}
font-size: 13px;
display: inline-block;
color: $inverted-text-color;
.emoji-mart-emoji {
padding: 6px;
}
@ -64,17 +64,17 @@
}
.emoji-mart-anchor-bar {
bottom: 0;
bottom: -1px;
}
}
.emoji-mart-anchor-bar {
position: absolute;
bottom: -3px;
bottom: -5px;
inset-inline-start: 0;
width: 100%;
height: 3px;
background-color: darken($ui-highlight-color, 3%);
height: 4px;
background-color: $highlight-text-color;
}
.emoji-mart-anchors {
@ -173,7 +173,7 @@
}
&:hover::before {
z-index: 0;
z-index: -1;
content: '';
position: absolute;
top: 0;

View File

@ -13,8 +13,9 @@
@import 'forms';
@import 'accounts';
@import 'statuses';
@import 'components/index';
@import 'components';
@import 'polls';
@import 'emoji_picker';
@import 'about';
@import 'tables';
@import 'admin';
@ -22,3 +23,5 @@
@import 'rtl';
@import 'dashboard';
@import 'rich_text';
@import 'glitch_local_settings';
@import 'glitch_doodle';

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M346-140 100-386q-10-10-15-22t-5-25q0-13 5-25t15-22l230-229-106-106 62-65 400 400q10 10 14.5 22t4.5 25q0 13-4.5 25T686-386L440-140q-10 10-22 15t-25 5q-13 0-25-5t-22-15Zm47-506L179-432h428L393-646Zm399 526q-36 0-61-25.5T706-208q0-27 13.5-51t30.5-47l42-54 44 54q16 23 30 47t14 51q0 37-26 62.5T792-120Z"/></svg>

After

Width:  |  Height:  |  Size: 405 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M346-140 100-386q-10-10-15-22t-5-25q0-13 5-25t15-22l230-229-106-106 62-65 400 400q10 10 14.5 22t4.5 25q0 13-4.5 25T686-386L440-140q-10 10-22 15t-25 5q-13 0-25-5t-22-15Zm47-506L179-432h428L393-646Zm399 526q-36 0-61-25.5T706-208q0-27 13.5-51t30.5-47l42-54 44 54q16 23 30 47t14 51q0 37-26 62.5T792-120Z"/></svg>

After

Width:  |  Height:  |  Size: 405 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M280-200v-80h284q63 0 109.5-40T720-420q0-60-46.5-100T564-560H312l104 104-56 56-200-200 200-200 56 56-104 104h252q97 0 166.5 63T800-420q0 94-69.5 157T564-200H280Z"/></svg>

After

Width:  |  Height:  |  Size: 267 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M280-200v-80h284q63 0 109.5-40T720-420q0-60-46.5-100T564-560H312l104 104-56 56-200-200 200-200 56 56-104 104h252q97 0 166.5 63T800-420q0 94-69.5 157T564-200H280Z"/></svg>

After

Width:  |  Height:  |  Size: 267 B

View File

@ -4,14 +4,34 @@ module ApplicationExtension
extend ActiveSupport::Concern
included do
include Redisable
has_many :created_users, class_name: 'User', foreign_key: 'created_by_application_id', inverse_of: :created_by_application
validates :name, length: { maximum: 60 }
validates :website, url: true, length: { maximum: 2_000 }, if: :website?
validates :redirect_uri, length: { maximum: 2_000 }
# The relationship used between Applications and AccessTokens is using
# dependent: delete_all, which means the ActiveRecord callback in
# AccessTokenExtension is not run, so instead we manually announce to
# streaming that these tokens are being deleted.
before_destroy :push_to_streaming_api, prepend: true
end
def confirmation_redirect_uri
redirect_uri.lines.first.strip
end
def push_to_streaming_api
# TODO: #28793 Combine into a single topic
payload = Oj.dump(event: :kill)
access_tokens.in_batches do |tokens|
redis.pipelined do |pipeline|
tokens.ids.each do |id|
pipeline.publish("timeline:access_token:#{id}", payload)
end
end
end
end
end

View File

@ -25,7 +25,15 @@ module User::LdapAuthenticable
resource = joins(:account).find_by(accounts: { username: safe_username })
if resource.blank?
resource = new(email: attributes[Devise.ldap_mail.to_sym].first, agreement: true, account_attributes: { username: safe_username }, admin: false, external: true, confirmed_at: Time.now.utc)
resource = new(
email: attributes[Devise.ldap_mail.to_sym].first,
agreement: true,
account_attributes: {
username: safe_username,
},
external: true,
confirmed_at: Time.now.utc
)
resource.save!
end

View File

@ -19,17 +19,18 @@ module User::Omniauthable
end
class_methods do
def find_for_oauth(auth, signed_in_resource = nil)
def find_for_omniauth(auth, signed_in_resource = nil)
# EOLE-SSO Patch
auth.uid = (auth.uid[0][:uid] || auth.uid[0][:user]) if auth.uid.is_a? Hashie::Array
identity = Identity.find_for_oauth(auth)
identity = Identity.find_for_omniauth(auth)
# If a signed_in_resource is provided it always overrides the existing user
# to prevent the identity being locked with accidentally created accounts.
# Note that this may leave zombie accounts (with no associated identity) which
# can be cleaned up at a later date.
user = signed_in_resource || identity.user
user ||= create_for_oauth(auth)
user ||= reattach_for_auth(auth)
user ||= create_for_auth(auth)
if identity.user.nil?
identity.user = user
@ -39,19 +40,35 @@ module User::Omniauthable
user
end
def create_for_oauth(auth)
# Check if the user exists with provided email. If no email was provided,
private
def reattach_for_auth(auth)
# If allowed, check if a user exists with the provided email address,
# and return it if they does not have an associated identity with the
# current authentication provider.
# This can be used to provide a choice of alternative auth providers
# or provide smooth gradual transition between multiple auth providers,
# but this is discouraged because any insecure provider will put *all*
# local users at risk, regardless of which provider they registered with.
return unless ENV['ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH'] == 'true'
email, email_is_verified = email_from_auth(auth)
return unless email_is_verified
user = User.find_by(email: email)
return if user.nil? || Identity.exists?(provider: auth.provider, user_id: user.id)
user
end
def create_for_auth(auth)
# Create a user for the given auth params. If no email was provided,
# we assign a temporary email and ask the user to verify it on
# the next step via Auth::SetupController.show
strategy = Devise.omniauth_configs[auth.provider.to_sym].strategy
assume_verified = strategy&.security&.assume_email_is_verified
email_is_verified = auth.info.verified || auth.info.verified_email || auth.info.email_verified || assume_verified
email = auth.info.verified_email || auth.info.email
user = User.find_by(email: email) if email_is_verified
return user unless user.nil?
email, email_is_verified = email_from_auth(auth)
user = User.new(user_params_from_auth(email, auth))
@ -66,7 +83,14 @@ module User::Omniauthable
user
end
private
def email_from_auth(auth)
strategy = Devise.omniauth_configs[auth.provider.to_sym].strategy
assume_verified = strategy&.security&.assume_email_is_verified
email_is_verified = auth.info.verified || auth.info.verified_email || auth.info.email_verified || assume_verified
email = auth.info.verified_email || auth.info.email
[email, email_is_verified]
end
def user_params_from_auth(email, auth)
{

View File

@ -32,7 +32,6 @@ module User::PamAuthenticable
self.email = "#{account.username}@#{find_pam_suffix}" if email.nil? && find_pam_suffix
self.confirmed_at = Time.now.utc
self.admin = false
self.account = account
self.external = true

View File

@ -17,7 +17,7 @@ class Identity < ApplicationRecord
validates :uid, presence: true, uniqueness: { scope: :provider }
validates :provider, presence: true
def self.find_for_oauth(auth)
def self.find_for_omniauth(auth)
find_or_create_by(uid: auth.uid, provider: auth.provider)
end
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
class TagFeed < PublicFeed
LIMIT_PER_MODE = 4
LIMIT_PER_MODE = (ENV['MAX_FEED_HASHTAGS'] || 4).to_i
# @param [Tag] tag
# @param [Account] account

View File

@ -51,6 +51,8 @@ class User < ApplicationRecord
last_sign_in_ip
skip_sign_in_token
filtered_languages
admin
moderator
)
include LanguagesHelper
@ -342,6 +344,16 @@ class User < ApplicationRecord
Doorkeeper::AccessToken.by_resource_owner(self).in_batches do |batch|
batch.update_all(revoked_at: Time.now.utc)
Web::PushSubscription.where(access_token_id: batch).delete_all
# Revoke each access token for the Streaming API, since `update_all``
# doesn't trigger ActiveRecord Callbacks:
# TODO: #28793 Combine into a single topic
payload = Oj.dump(event: :kill)
redis.pipelined do |pipeline|
batch.ids.each do |id|
pipeline.publish("timeline:access_token:#{id}", payload)
end
end
end
end

View File

@ -5,7 +5,7 @@ class InitialStateSerializer < ActiveModel::Serializer
attributes :meta, :compose, :accounts,
:media_attachments, :settings,
:max_toot_chars, :poll_limits,
:max_toot_chars, :max_feed_hashtags, :poll_limits,
:languages
attribute :critical_updates_pending, if: -> { object&.role&.can?(:view_devops) && SoftwareUpdate.check_enabled? }
@ -17,6 +17,10 @@ class InitialStateSerializer < ActiveModel::Serializer
StatusLengthValidator::MAX_CHARS
end
def max_feed_hashtags
TagFeed::LIMIT_PER_MODE
end
def poll_limits
{
max_options: PollValidator::MAX_OPTIONS,

View File

@ -44,7 +44,7 @@ class FetchResourceService < BaseService
@response_code = response.code
return nil if response.code != 200
if ['application/activity+json', 'application/ld+json'].include?(response.mime_type)
if valid_activitypub_content_type?(response)
body = response.body_with_limit
json = body_to_json(body)

View File

@ -8,9 +8,7 @@
%td.email-inner-card-td.email-prose
%p= t @resource.approved? ? 'devise.mailer.confirmation_instructions.explanation' : 'devise.mailer.confirmation_instructions.explanation_when_pending', host: site_hostname
- if @resource.created_by_application
= render 'application/mailer/button', text: t('settings.account_settings'), url: edit_user_registration_url
= link_to confirmation_url(@resource, confirmation_token: @token, redirect_to_app: 'true') do
%span= t 'devise.mailer.confirmation_instructions.action_with_app', app: @resource.created_by_application.name
= render 'application/mailer/button', text: t('devise.mailer.confirmation_instructions.action_with_app', app: @resource.created_by_application.name), url: confirmation_url(@resource, confirmation_token: @token, redirect_to_app: 'true')
- else
= render 'application/mailer/button', text: t('devise.mailer.confirmation_instructions.action'), url: confirmation_url(@resource, confirmation_token: @token)
%p= t 'devise.mailer.confirmation_instructions.extra_html', terms_path: about_more_url, policy_path: privacy_policy_url

View File

@ -21,9 +21,14 @@ Doorkeeper.configure do
user unless user&.otp_required_for_login?
end
# If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below.
# Doorkeeper provides some administrative interfaces for managing OAuth
# Applications, allowing creation, edit, and deletion of applications from the
# server. At present, these administrative routes are not integrated into
# Mastodon, and as such, we've disabled them by always return a 403 forbidden
# response for them. This does not affect the ability for users to manage
# their own OAuth Applications.
admin_authenticator do
current_user&.admin? || redirect_to(new_user_session_url)
head 403
end
# Authorization Code expiration time (default 10 minutes).

View File

@ -26,6 +26,7 @@ Sidekiq.configure_server do |config|
'queue' => 'scheduler',
},
}
SidekiqScheduler::Scheduler.instance.reload_schedule!
end
end

View File

@ -12,6 +12,7 @@ en:
last_attempt: You have one more attempt before your account is locked.
locked: Your account is locked.
not_found_in_database: Invalid %{authentication_keys} or password.
omniauth_user_creation_failure: Error creating an account for this identity.
pending: Your account is still under review.
timeout: Your session expired. Please login again to continue.
unauthenticated: You need to login or sign up before continuing.

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'sidekiq_unique_jobs/web'
require 'sidekiq_unique_jobs/web' if ENV['ENABLE_SIDEKIQ_UNIQUE_JOBS_UI'] == true
require 'sidekiq-scheduler/web'
class RedirectWithVary < ActionDispatch::Routing::PathRedirect

View File

@ -56,7 +56,7 @@ services:
web:
build: .
image: ghcr.io/mastodon/mastodon:v4.2.0
image: ghcr.io/mastodon/mastodon:v4.2.7
restart: always
env_file: .env.production
command: bundle exec puma -C config/puma.rb
@ -77,7 +77,7 @@ services:
streaming:
build: .
image: ghcr.io/mastodon/mastodon:v4.2.0
image: ghcr.io/mastodon/mastodon:v4.2.7
restart: always
env_file: .env.production
command: node ./streaming
@ -95,7 +95,7 @@ services:
sidekiq:
build: .
image: ghcr.io/mastodon/mastodon:v4.2.0
image: ghcr.io/mastodon/mastodon:v4.2.7
restart: always
env_file: .env.production
command: bundle exec sidekiq

View File

@ -17,7 +17,7 @@ module Mastodon
end
def default_prerelease
'alpha.1'
'alpha.3'
end
def prerelease

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
namespace :sidekiq_unique_jobs do
task delete_all_locks: :environment do
digests = SidekiqUniqueJobs::Digests.new
digests.delete_by_pattern('*', count: digests.count)
expiring_digests = SidekiqUniqueJobs::ExpiringDigests.new
expiring_digests.delete_by_pattern('*', count: expiring_digests.count)
end
end

View File

@ -56,15 +56,15 @@ describe JsonLdHelper do
describe '#fetch_resource' do
context 'when the second argument is false' do
it 'returns resource even if the retrieved ID and the given URI does not match' do
stub_request(:get, 'https://bob.test/').to_return body: '{"id": "https://alice.test/"}'
stub_request(:get, 'https://alice.test/').to_return body: '{"id": "https://alice.test/"}'
stub_request(:get, 'https://bob.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://alice.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' })
expect(fetch_resource('https://bob.test/', false)).to eq({ 'id' => 'https://alice.test/' })
end
it 'returns nil if the object identified by the given URI and the object identified by the retrieved ID does not match' do
stub_request(:get, 'https://mallory.test/').to_return body: '{"id": "https://marvin.test/"}'
stub_request(:get, 'https://marvin.test/').to_return body: '{"id": "https://alice.test/"}'
stub_request(:get, 'https://mallory.test/').to_return(body: '{"id": "https://marvin.test/"}', headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://marvin.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' })
expect(fetch_resource('https://mallory.test/', false)).to be_nil
end
@ -72,7 +72,7 @@ describe JsonLdHelper do
context 'when the second argument is true' do
it 'returns nil if the retrieved ID and the given URI does not match' do
stub_request(:get, 'https://mallory.test/').to_return body: '{"id": "https://alice.test/"}'
stub_request(:get, 'https://mallory.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' })
expect(fetch_resource('https://mallory.test/', true)).to be_nil
end
end
@ -80,12 +80,12 @@ describe JsonLdHelper do
describe '#fetch_resource_without_id_validation' do
it 'returns nil if the status code is not 200' do
stub_request(:get, 'https://host.test/').to_return status: 400, body: '{}'
stub_request(:get, 'https://host.test/').to_return(status: 400, body: '{}', headers: { 'Content-Type': 'application/activity+json' })
expect(fetch_resource_without_id_validation('https://host.test/')).to be_nil
end
it 'returns hash' do
stub_request(:get, 'https://host.test/').to_return status: 200, body: '{}'
stub_request(:get, 'https://host.test/').to_return(status: 200, body: '{}', headers: { 'Content-Type': 'application/activity+json' })
expect(fetch_resource_without_id_validation('https://host.test/')).to eq({})
end
end

View File

@ -35,7 +35,7 @@ RSpec.describe ActivityPub::Activity::Announce do
context 'when sender is followed by a local account' do
before do
Fabricate(:account).follow!(sender)
stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json))
stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json), headers: { 'Content-Type': 'application/activity+json' })
subject.perform
end
@ -120,7 +120,7 @@ RSpec.describe ActivityPub::Activity::Announce do
let(:object_json) { 'https://example.com/actor/hello-world' }
before do
stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json))
stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json), headers: { 'Content-Type': 'application/activity+json' })
end
context 'when the relay is enabled' do

View File

@ -3,19 +3,19 @@
require 'rails_helper'
RSpec.describe Identity do
describe '.find_for_oauth' do
describe '.find_for_omniauth' do
let(:auth) { Fabricate(:identity, user: Fabricate(:user)) }
it 'calls .find_or_create_by' do
allow(described_class).to receive(:find_or_create_by)
described_class.find_for_oauth(auth)
described_class.find_for_omniauth(auth)
expect(described_class).to have_received(:find_or_create_by).with(uid: auth.uid, provider: auth.provider)
end
it 'returns an instance of Identity' do
expect(described_class.find_for_oauth(auth)).to be_instance_of described_class
expect(described_class.find_for_omniauth(auth)).to be_instance_of described_class
end
end
end

View File

@ -438,7 +438,10 @@ RSpec.describe User do
let!(:access_token) { Fabricate(:access_token, resource_owner_id: user.id) }
let!(:web_push_subscription) { Fabricate(:web_push_subscription, access_token: access_token) }
let(:redis_pipeline_stub) { instance_double(Redis::Namespace, publish: nil) }
before do
allow(redis).to receive(:pipelined).and_yield(redis_pipeline_stub)
user.reset_password!
end
@ -455,6 +458,10 @@ RSpec.describe User do
expect(Doorkeeper::AccessToken.active_for(user).count).to eq 0
end
it 'revokes streaming access for all access tokens' do
expect(redis_pipeline_stub).to have_received(:publish).with("timeline:access_token:#{access_token.id}", Oj.dump(event: :kill)).once
end
it 'removes push subscriptions' do
expect(Web::PushSubscription.where(user: user).or(Web::PushSubscription.where(access_token: access_token)).count).to eq 0
expect { web_push_subscription.reload }.to raise_error(ActiveRecord::RecordNotFound)

View File

@ -0,0 +1,83 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Disabled OAuth routes' do
# These routes are disabled via the doorkeeper configuration for
# `admin_authenticator`, as these routes should only be accessible by server
# administrators. For now, these routes are not properly designed and
# integrated into Mastodon, so we're disabling them completely
describe 'GET /oauth/applications' do
it 'returns 403 forbidden' do
get oauth_applications_path
expect(response).to have_http_status(403)
end
end
describe 'POST /oauth/applications' do
it 'returns 403 forbidden' do
post oauth_applications_path
expect(response).to have_http_status(403)
end
end
describe 'GET /oauth/applications/new' do
it 'returns 403 forbidden' do
get new_oauth_application_path
expect(response).to have_http_status(403)
end
end
describe 'GET /oauth/applications/:id' do
let(:application) { Fabricate(:application, scopes: 'read') }
it 'returns 403 forbidden' do
get oauth_application_path(application)
expect(response).to have_http_status(403)
end
end
describe 'PATCH /oauth/applications/:id' do
let(:application) { Fabricate(:application, scopes: 'read') }
it 'returns 403 forbidden' do
patch oauth_application_path(application)
expect(response).to have_http_status(403)
end
end
describe 'PUT /oauth/applications/:id' do
let(:application) { Fabricate(:application, scopes: 'read') }
it 'returns 403 forbidden' do
put oauth_application_path(application)
expect(response).to have_http_status(403)
end
end
describe 'DELETE /oauth/applications/:id' do
let(:application) { Fabricate(:application, scopes: 'read') }
it 'returns 403 forbidden' do
delete oauth_application_path(application)
expect(response).to have_http_status(403)
end
end
describe 'GET /oauth/applications/:id/edit' do
let(:application) { Fabricate(:application, scopes: 'read') }
it 'returns 403 forbidden' do
get edit_oauth_application_path(application)
expect(response).to have_http_status(403)
end
end
end

View File

@ -39,16 +39,35 @@ describe 'OmniAuth callbacks' do
Fabricate(:user, email: 'user@host.example')
end
it 'matches the existing user, creates an identity, and redirects to root path' do
expect { subject }
.to not_change(User, :count)
.and change(Identity, :count)
.by(1)
.and change(LoginActivity, :count)
.by(1)
context 'when ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH is set to true' do
around do |example|
ClimateControl.modify ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH: 'true' do
example.run
end
end
expect(Identity.find_by(user: User.last).uid).to eq('123')
expect(response).to redirect_to(root_path)
it 'matches the existing user, creates an identity, and redirects to root path' do
expect { subject }
.to not_change(User, :count)
.and change(Identity, :count)
.by(1)
.and change(LoginActivity, :count)
.by(1)
expect(Identity.find_by(user: User.last).uid).to eq('123')
expect(response).to redirect_to(root_path)
end
end
context 'when ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH is not set to true' do
it 'does not match the existing user or create an identity, and redirects to login page' do
expect { subject }
.to not_change(User, :count)
.and not_change(Identity, :count)
.and not_change(LoginActivity, :count)
expect(response).to redirect_to(new_user_session_url)
end
end
end
@ -96,7 +115,7 @@ describe 'OmniAuth callbacks' do
context 'when a user cannot be built' do
before do
allow(User).to receive(:find_for_oauth).and_return(User.new)
allow(User).to receive(:find_for_omniauth).and_return(User.new)
end
it 'redirects to the new user signup page' do

View File

@ -72,11 +72,11 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
shared_examples 'sets pinned posts' do
before do
stub_request(:get, 'https://example.com/account/pinned/known').to_return(status: 200, body: Oj.dump(status_json_pinned_known))
stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined))
stub_request(:get, 'https://example.com/account/pinned/known').to_return(status: 200, body: Oj.dump(status_json_pinned_known), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/account/pinned/unknown-unreachable').to_return(status: 404)
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable))
stub_request(:get, 'https://example.com/account/collections/featured').to_return(status: 200, body: Oj.dump(featured_with_null))
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/account/collections/featured').to_return(status: 200, body: Oj.dump(featured_with_null), headers: { 'Content-Type': 'application/activity+json' })
subject.call(actor, note: true, hashtag: false)
end
@ -94,7 +94,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
describe '#call' do
context 'when the endpoint is a Collection' do
before do
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
end
it_behaves_like 'sets pinned posts'
@ -111,7 +111,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
end
before do
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
end
it_behaves_like 'sets pinned posts'
@ -120,7 +120,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
let(:items) { 'https://example.com/account/pinned/unknown-reachable' }
before do
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable))
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' })
subject.call(actor, note: true, hashtag: false)
end
@ -147,7 +147,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
end
before do
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
end
it_behaves_like 'sets pinned posts'
@ -156,7 +156,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
let(:items) { 'https://example.com/account/pinned/unknown-reachable' }
before do
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable))
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' })
subject.call(actor, note: true, hashtag: false)
end

View File

@ -38,7 +38,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d
describe '#call' do
context 'when the endpoint is a Collection' do
before do
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
end
it_behaves_like 'sets featured tags'
@ -46,7 +46,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d
context 'when the account already has featured tags' do
before do
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
actor.featured_tags.create!(name: 'FoO')
actor.featured_tags.create!(name: 'baz')
@ -67,7 +67,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d
end
before do
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
end
it_behaves_like 'sets featured tags'
@ -88,7 +88,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d
end
before do
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
end
it_behaves_like 'sets featured tags'

View File

@ -44,7 +44,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
before do
actor[:inbox] = nil
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
end
@ -67,7 +67,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
before do
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
end
@ -93,7 +93,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
before do
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
end
@ -125,7 +125,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
before do
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
end
@ -148,7 +148,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
before do
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
end

View File

@ -44,7 +44,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
before do
actor[:inbox] = nil
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
end
@ -67,7 +67,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
before do
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
end
@ -93,7 +93,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
before do
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
end
@ -125,7 +125,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
before do
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
end
@ -148,7 +148,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
before do
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
end

View File

@ -50,7 +50,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do
end
before do
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
end
@ -59,7 +59,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do
context 'when the key is a sub-object from the actor' do
before do
stub_request(:get, public_key_id).to_return(body: Oj.dump(actor))
stub_request(:get, public_key_id).to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
end
it 'returns the expected account' do
@ -71,7 +71,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do
let(:public_key_id) { 'https://example.com/alice-public-key.json' }
before do
stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })))
stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })), headers: { 'Content-Type': 'application/activity+json' })
end
it 'returns the expected account' do
@ -84,7 +84,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do
let(:actor_public_key) { 'https://example.com/alice-public-key.json' }
before do
stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })))
stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })), headers: { 'Content-Type': 'application/activity+json' })
end
it 'returns the nil' do

View File

@ -58,7 +58,7 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do
context 'when passing the URL to the collection' do
before do
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
end
it 'spawns workers for up to 5 replies on the same server' do
@ -93,7 +93,7 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do
context 'when passing the URL to the collection' do
before do
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
end
it 'spawns workers for up to 5 replies on the same server' do
@ -132,7 +132,7 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do
context 'when passing the URL to the collection' do
before do
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
end
it 'spawns workers for up to 5 replies on the same server' do

View File

@ -60,7 +60,7 @@ RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do
describe '#call' do
context 'when the endpoint is a Collection of actor URIs' do
before do
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
end
it_behaves_like 'synchronizes followers'
@ -77,7 +77,7 @@ RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do
end
before do
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
end
it_behaves_like 'synchronizes followers'
@ -98,7 +98,7 @@ RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do
end
before do
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
end
it_behaves_like 'synchronizes followers'

View File

@ -21,7 +21,7 @@ describe ActivityPub::FetchRepliesWorker do
describe 'perform' do
it 'performs a request if the collection URI is from the same host' do
stub_request(:get, 'https://example.com/statuses_replies/1').to_return(status: 200, body: json)
stub_request(:get, 'https://example.com/statuses_replies/1').to_return(status: 200, body: json, headers: { 'Content-Type': 'application/activity+json' })
subject.perform(status.id, 'https://example.com/statuses_replies/1')
expect(a_request(:get, 'https://example.com/statuses_replies/1')).to have_been_made.once
end