diff --git a/.circleci/config.yml b/.circleci/config.yml index 2a60ae6841..bddfd2d27a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -68,7 +68,9 @@ jobs: cache-version: v1 pkg-manager: yarn - run: - command: ./bin/rails assets:precompile + command: | + export NODE_OPTIONS=--openssl-legacy-provider + ./bin/rails assets:precompile name: Precompile assets - persist_to_workspace: paths: diff --git a/.env.production.catcatnya b/.env.production.catcatnya new file mode 100644 index 0000000000..e99422ecc4 --- /dev/null +++ b/.env.production.catcatnya @@ -0,0 +1,44 @@ +LOCAL_DOMAIN=catcatnya.com +ALTERNATE_DOMAINS=0.catcatnya.com,1.catcatnya.com,2.catcatnya.com,3.catcatnya.com,4.catcatnya.com,5.catcatnya.com,6.catcatnya.com,7.catcatnya.com,8.catcatnya.com,9.catcatnya.com +SINGLE_USER_MODE=false +SECRET_KEY_BASE=[REDACTED] +OTP_SECRET=[REDACTED] +VAPID_PRIVATE_KEY=[REDACTED] +VAPID_PUBLIC_KEY=[REDACTED] +DB_HOST=[REDACTED] +DB_PORT=[REDACTED] +DB_NAME=[REDACTED] +DB_USER=[REDACTED] +DB_PASS=[REDACTED] +REDIS_HOST=[REDACTED] +REDIS_PORT=[REDACTED] +REDIS_PASSWORD=[REDACTED] +S3_ENABLED=false +PAPERCLIP_ROOT_PATH=[REDACTED] +PAPERCLIP_ROOT_URL=https://cdn.catcatnya.com +SMTP_SERVER=smtp.kescher.at +SMTP_PORT=[REDACTED] +SMTP_LOGIN=[REDACTED] +SMTP_PASSWORD=[REDACTED] +SMTP_AUTH_METHOD=[REDACTED] +SMTP_OPENSSL_VERIFY_MODE=[REDACTED] +SMTP_FROM_ADDRESS='Mastodon ' +ES_ENABLED=true +ES_HOST=[REDACTED] +ES_PORT=[REDACTED] +ES_PREFIX=[REDACTED] +AUTHORIZED_FETCH=true +RAILS_SERVE_STATIC_FILES=false +RAILS_LOG_LEVEL=error + +MAX_TOOT_CHARS=6942 +MAX_DESCRIPTION_CHARS=6942 +MAX_BIO_CHARS=6942 +MAX_PROFILE_FIELDS=10 +MAX_PINNED_TOOTS=10 +MAX_DISPLAY_NAME_CHARS=50 +MIN_POLL_OPTIONS=1 +MAX_POLL_OPTIONS=20 +MAX_SEARCH_RESULTS=1000 +MAX_REMOTE_EMOJI_SIZE=1048576 +IP_RETENTION_PERIOD=86400 diff --git a/.env.production.sample b/.env.production.sample index ae5d6c3687..8ecca9d604 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -263,6 +263,9 @@ MAX_PROFILE_FIELDS=4 # Maximum allowed display name characters MAX_DISPLAY_NAME_CHARS=30 +# Minimum allowed poll options. (Minimum of 1) +MIN_POLL_OPTIONS=2 + # Maximum allowed poll options MAX_POLL_OPTIONS=5 diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml deleted file mode 100644 index 3a880fabf2..0000000000 --- a/.github/workflows/build-image.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Build container image -on: - workflow_dispatch: - push: - branches: - - 'main' - pull_request: - paths: - - .github/workflows/build-image.yml - - Dockerfile -permissions: - contents: read - packages: write - -jobs: - build-image: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: docker/setup-qemu-action@v2 - - uses: docker/setup-buildx-action@v2 - - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - if: github.event_name != 'pull_request' - - uses: docker/metadata-action@v4 - id: meta - with: - images: ghcr.io/${{ github.repository_owner }}/mastodon - tags: | - type=raw,value=latest,enable={{is_default_branch}} - type=edge,branch=main - type=sha,prefix=,format=long - - uses: docker/build-push-action@v3 - with: - context: . - platforms: linux/amd64,linux/arm64 - builder: ${{ steps.buildx.outputs.name }} - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - cache-from: type=gha - cache-to: type=gha,mode=max diff --git a/.ruby-version b/.ruby-version index b0f2dcb32f..eca690e737 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.0.4 +3.0.5 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index cc0a7f51b0..4529bd2d82 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at glitch-abuse@sitedethib.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at jeremy@kescher.at. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 049cd4e29b..e466cf104a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,25 +1,24 @@ -# Contributing to Mastodon Glitch Edition # +# Contributing to Catstodon # -Thank you for your interest in contributing to the `glitch-soc` project! -Here are some guidelines, and ways you can help. +Thank you for your interest in contributing to a fork of the `glitch-soc` project! +Before you do anything here, please check if you can contribute to either the [vanilla Mastodon project](https://github.com/mastodon/mastodon) or [glitch-soc](https://github.com/glitch-soc/mastodon) first. +If you still decide to contribute here instead, here are some guidelines, and ways you can help. > (This document is a bit of a work-in-progress, so please bear with us. > If you don't see what you're looking for here, please don't hesitate to reach out!) ## Planning ## -Right now a lot of the planning for this project takes place in our development Discord, or through GitHub Issues and Projects. -We're working on ways to improve the planning structure and better solicit feedback, and if you feel like you can help in this respect, feel free to give us a holler. +Right now a lot of the planning for this project takes place... in my head. Actually, just contact me via Matrix - contact info can be found on [my personal website](https://kescher.at). You can also contribute via GitHub or kescherGit, if you have an account at either. ## Documentation ## -The documentation for this repository is available at [`glitch-soc/docs`](https://github.com/glitch-soc/docs) (online at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/)). -Right now, we've mostly focused on the features that make this fork different from upstream in some manner. -Adding screenshots, improving descriptions, and so forth are all ways to help contribute to the project even if you don't know any code. +Unlike glitch-soc, which has [`glitch-soc/docs`](https://github.com/glitch-soc/docs) (online at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/)), this repo only documents things in a README. Sorry. +Right now, we've mostly focused on the features that make this fork different from upstream, which, may I remind you, is already a fork. ## Frontend Development ## -Check out [the documentation here](https://glitch-soc.github.io/docs/contributing/frontend/) for more information. +Check out [the documentation here](https://glitch-soc.github.io/docs/contributing/frontend/) for more information on this topic. We'll be following that a bit. ## Backend Development ## diff --git a/Gemfile.lock b/Gemfile.lock index 237edb61ce..10ade23068 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -90,22 +90,22 @@ GEM attr_required (1.0.1) awrence (1.2.1) aws-eventstream (1.2.0) - aws-partitions (1.587.0) - aws-sdk-core (3.130.2) + aws-partitions (1.668.0) + aws-sdk-core (3.168.2) aws-eventstream (~> 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.525.0) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.5) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.60.0) + aws-sdk-core (~> 3, >= 3.165.0) aws-sigv4 (~> 1.1) - jmespath (~> 1.0) - aws-sdk-kms (1.56.0) - aws-sdk-core (~> 3, >= 3.127.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.114.0) - aws-sdk-core (~> 3, >= 3.127.0) + aws-sdk-s3 (1.117.1) + aws-sdk-core (~> 3, >= 3.165.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.4) - aws-sigv4 (1.5.0) + aws-sigv4 (1.5.2) aws-eventstream (~> 1, >= 1.0.2) - bcrypt (3.1.17) + bcrypt (3.1.18) better_errors (2.9.1) coderay (>= 1.0.0) erubi (>= 1.0.0) @@ -117,7 +117,7 @@ GEM erubi (~> 1.4) parser (>= 2.4) smart_properties - bindata (2.4.10) + bindata (2.4.14) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) blurhash (0.1.6) @@ -125,12 +125,12 @@ GEM bootsnap (1.14.0) msgpack (~> 1.2) brakeman (5.4.0) - browser (4.2.0) - brpoplpush-redis_script (0.1.2) + browser (5.3.1) + brpoplpush-redis_script (0.1.3) concurrent-ruby (~> 1.0, >= 1.0.5) - redis (>= 1.0, <= 5.0) + redis (>= 1.0, < 6) builder (3.2.4) - bullet (7.0.3) + bullet (7.0.4) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) bundler-audit (0.9.1) @@ -142,7 +142,7 @@ GEM i18n rake (>= 10.0.0) sshkit (>= 1.9.0) - capistrano-bundler (2.0.1) + capistrano-bundler (2.1.0) capistrano (~> 3.1) capistrano-rails (1.6.2) capistrano (~> 3.1) @@ -165,7 +165,7 @@ GEM activesupport cbor (0.5.9.6) charlock_holmes (0.7.7) - chewy (7.2.4) + chewy (7.2.7) activesupport (>= 5.2) elasticsearch (>= 7.12.0, < 7.14.0) elasticsearch-dsl @@ -176,15 +176,15 @@ GEM color_diff (0.1) concurrent-ruby (1.1.10) connection_pool (2.3.0) - cose (1.2.1) + cose (1.3.0) cbor (~> 0.5.9) openssl-signature_algorithm (~> 1.0) crack (0.4.5) rexml crass (1.0.6) - css_parser (1.7.1) + css_parser (1.12.0) addressable - debug_inspector (1.0.0) + debug_inspector (1.1.0) devise (4.8.1) bcrypt (~> 3.0) orm_adapter (~> 0.1) @@ -203,10 +203,10 @@ GEM diff-lcs (1.5.0) discard (1.2.1) activerecord (>= 4.2, < 8) - docile (1.3.4) + docile (1.4.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - doorkeeper (5.6.0) + doorkeeper (5.6.2) railties (>= 5) dotenv (2.8.1) dotenv-rails (2.8.1) @@ -226,11 +226,11 @@ GEM erubi (1.11.0) et-orbi (1.2.7) tzinfo - excon (0.76.0) + excon (0.94.0) fabrication (2.30.0) faker (2.23.0) i18n (>= 1.8.11, < 2) - faraday (1.9.3) + faraday (1.10.2) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -246,8 +246,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.3) - multipart-post (>= 1.2, < 3) + faraday-multipart (1.0.4) + multipart-post (~> 2) faraday-net_http (1.0.1) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) @@ -271,8 +271,8 @@ GEM fog-core (>= 1.45, <= 2.1.0) fog-json (>= 1.0) ipaddress (>= 0.8) - formatador (0.2.5) - fugit (1.7.1) + formatador (0.3.0) + fugit (1.7.2) et-orbi (~> 1, >= 1.2.7) raabro (~> 1.4) fuubar (2.5.1) @@ -284,7 +284,7 @@ GEM openid_connect (~> 1.2) globalid (1.0.0) activesupport (>= 5.0) - hamlit (2.13.0) + hamlit (3.0.3) temple (>= 0.8.2) thor tilt @@ -329,13 +329,14 @@ GEM terminal-table (>= 1.5.1) idn-ruby (0.1.5) ipaddress (0.8.3) - jmespath (1.6.1) + jmespath (1.6.2) json (2.6.2) - json-canonicalization (0.3.0) - json-jwt (1.13.0) + json-canonicalization (0.3.1) + json-jwt (1.15.3) activesupport (>= 4.2) aes_key_wrap bindata + httpclient json-ld (3.2.3) htmlentities (~> 4.3) json-canonicalization (~> 0.3) @@ -347,7 +348,7 @@ GEM json-ld (~> 3.2) rdf (~> 3.2) jsonapi-renderer (0.2.2) - jwt (2.4.1) + jwt (2.5.0) kaminari (1.2.2) activesupport (>= 4.1.0) kaminari-actionview (= 1.2.2) @@ -404,18 +405,20 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2022.0105) mini_mime (1.1.2) - mini_portile2 (2.8.0) minitest (5.16.3) msgpack (1.6.0) multi_json (1.15.0) - multipart-post (2.1.1) + multipart-post (2.2.3) net-ldap (0.17.1) - net-scp (4.0.0.rc1) + net-protocol (0.1.3) + timeout + net-scp (4.0.0) net-ssh (>= 2.6.5, < 8.0.0) + net-smtp (0.3.3) + net-protocol net-ssh (7.0.1) nio4r (2.5.8) - nokogiri (1.13.9) - mini_portile2 (~> 2.8.0) + nokogiri (1.13.9-x86_64-linux) racc (~> 1.4) nsa (0.2.8) activesupport (>= 4.2, < 7) @@ -436,23 +439,24 @@ GEM omniauth-saml (1.10.3) omniauth (~> 1.3, >= 1.3.2) ruby-saml (~> 1.9) - openid_connect (1.3.0) + openid_connect (1.4.2) activemodel attr_required (>= 1.0.0) - json-jwt (>= 1.5.0) - rack-oauth2 (>= 1.6.1) - swd (>= 1.0.0) + json-jwt (>= 1.15.0) + net-smtp + rack-oauth2 (~> 1.21) + swd (~> 1.3) tzinfo validate_email validate_url - webfinger (>= 1.0.1) - openssl (3.0.0) + webfinger (~> 1.2) + openssl (3.0.1) openssl-signature_algorithm (1.2.1) openssl (> 2.0, < 3.1) orm_adapter (0.5.0) ox (2.14.11) parallel (1.22.1) - parser (3.1.2.1) + parser (3.1.3.0) ast (~> 2.4.1) parslet (2.0.0) pastel (0.8.0) @@ -460,14 +464,15 @@ GEM pg (1.4.5) pghero (2.8.3) activerecord (>= 5) - pkg-config (1.4.9) + pkg-config (1.5.1) posix-spawn (0.3.15) - premailer (1.14.2) + premailer (1.18.0) addressable - css_parser (>= 1.6.0) + css_parser (>= 1.12.0) htmlentities (>= 4.0.0) - premailer-rails (1.11.1) + premailer-rails (1.12.0) actionmailer (>= 3) + net-smtp premailer (~> 1.7, >= 1.7.9) private_address_check (0.5.0) pry (0.14.1) @@ -490,13 +495,13 @@ GEM rack (>= 1.0, < 3) rack-cors (1.1.1) rack (>= 2.0.0) - rack-oauth2 (1.19.0) + rack-oauth2 (1.21.3) activesupport attr_required httpclient json-jwt (>= 1.11.0) rack (>= 2.1.0) - rack-proxy (0.7.0) + rack-proxy (0.7.4) rack rack-test (2.0.2) rack (>= 1.3) @@ -527,7 +532,7 @@ GEM rails-i18n (6.0.0) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 7) - rails-settings-cached (0.6.6) + rails-settings-cached (0.7.2) rails (>= 4.2.0) railties (6.1.7) actionpack (= 6.1.7) @@ -539,33 +544,33 @@ GEM rake (13.0.6) rdf (3.2.9) link_header (~> 0.0, >= 0.0.8) - rdf-normalize (0.5.0) + rdf-normalize (0.5.1) rdf (~> 3.2) redcarpet (3.5.1) - redis (4.5.1) + redis (4.8.0) redis-namespace (1.9.0) redis (>= 4) - regexp_parser (2.6.0) + regexp_parser (2.6.1) request_store (1.5.1) rack (>= 1.4) responders (3.0.1) actionpack (>= 5.0) railties (>= 5.0) rexml (3.2.5) - rotp (6.2.0) + rotp (6.2.1) rpam2 (4.0.2) rqrcode (2.1.2) chunky_png (~> 1.0) rqrcode_core (~> 1.0) rqrcode_core (1.2.0) - rspec-core (3.11.0) - rspec-support (~> 3.11.0) - rspec-expectations (3.11.0) + rspec-core (3.12.0) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) - rspec-mocks (3.11.1) + rspec-support (~> 3.12.0) + rspec-mocks (3.12.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) + rspec-support (~> 3.12.0) rspec-rails (5.1.2) actionpack (>= 5.2) activesupport (>= 5.2) @@ -577,26 +582,27 @@ GEM rspec-sidekiq (3.1.0) rspec-core (~> 3.0, >= 3.0.0) sidekiq (>= 2.4.0) - rspec-support (3.11.1) + rspec-support (3.12.0) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.30.1) + rubocop (1.39.0) + json (~> 2.3) parallel (~> 1.10) - parser (>= 3.1.0.0) + parser (>= 3.1.2.1) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.18.0, < 2.0) + rubocop-ast (>= 1.23.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.18.0) + rubocop-ast (1.23.0) parser (>= 3.1.1.0) - rubocop-rails (2.15.0) + rubocop-rails (2.17.3) activesupport (>= 4.2.0) rack (>= 1.1) - rubocop (>= 1.7.0, < 2.0) + rubocop (>= 1.33.0, < 2.0) ruby-progressbar (1.11.0) - ruby-saml (1.13.0) + ruby-saml (1.14.0) nokogiri (>= 1.10.5) rexml ruby2_keywords (0.0.5) @@ -637,7 +643,7 @@ GEM simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) - simplecov_json_formatter (0.1.2) + simplecov_json_formatter (0.1.4) smart_properties (1.17.0) sprockets (3.7.2) concurrent-ruby (~> 1.0) @@ -646,25 +652,26 @@ GEM actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sshkit (1.21.2) + sshkit (1.21.3) net-scp (>= 1.1.2) net-ssh (>= 2.8.0) - stackprof (0.2.22) + stackprof (0.2.23) statsd-ruby (1.5.0) stoplight (3.0.0) - strong_migrations (0.7.9) - activerecord (>= 5) + strong_migrations (0.8.0) + activerecord (>= 5.2) swd (1.3.0) activesupport (>= 3) attr_required (>= 0.0.5) httpclient (>= 2.4) - temple (0.8.2) + temple (0.9.1) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) terrapin (0.6.0) climate_control (>= 0.0.3, < 1.0) thor (1.2.1) tilt (2.0.11) + timeout (0.3.0) tpm-key_attestation (0.11.0) bindata (~> 2.4) openssl (> 2.0, < 3.1) @@ -684,7 +691,7 @@ GEM unf (~> 0.1.0) tzinfo (2.0.5) concurrent-ruby (~> 1.0) - tzinfo-data (1.2022.6) + tzinfo-data (1.2022.7) tzinfo (>= 1.0.0) unf (0.1.4) unf_ext @@ -727,7 +734,7 @@ GEM xorcist (1.1.3) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.0) + zeitwerk (2.6.6) PLATFORMS ruby diff --git a/README.md b/README.md index 256f2d2def..646f67f217 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,35 @@ -# Mastodon Glitch Edition # +# Catstodon +## Introduction +This Mastodon fork is based on the [glitch-soc Fork of Mastodon](https://github.com/glitch-soc/mastodon), with changes made to suit [CatCatNya~](https://catcatnya.com). +The aforementioned instance is running the `develop` branch. +I intend to contribute some useful differences back to [glitch-soc](https://github.com/glitch-soc/mastodon) and [vanilla Mastodon](https://github.com/mastodon/mastodon). -> Now with automated deploys! +To install, take a look at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/). The instructions and features are the same, except for the differences outlined below. -[![Build Status](https://img.shields.io/circleci/project/github/glitch-soc/mastodon.svg)][circleci] -[![Code Climate](https://img.shields.io/codeclimate/maintainability/glitch-soc/mastodon.svg)][code_climate] +Contributing guidelines are available [here](CONTRIBUTING.md). -[circleci]: https://circleci.com/gh/glitch-soc/mastodon -[code_climate]: https://codeclimate.com/github/glitch-soc/mastodon +Note: [CatCatNya~](https://catcatnya.com) runs on the `develop` branch. +That branch may, at times, be force-pushed to (mostly for undoing cherry-picking of vanilla commits when upstream adopts them). +I highly suggest only ever running the `main` branch in production! -So here's the deal: we all work on this code, and anyone who uses that does so absolutely at their own risk. can you dig it? +## Differences +- Some files are adjusted specifically for the CatCatNya~ instance. Specifically, these: + - sounds/boop.mp3 + - sounds/boop.ogg +
You might want to revert these to the upstream files (or your own versions!) if you decide to use this fork for your own instance. +- The web frontend emoji picker is a blobcat instead of the joy emoji. +- The rate limits for authenticated users have been relaxed a bit. +- The API endpoint `/api/v1/custom_emojis` is no longer affected by AUTHORIZED_FETCH, allowing anyone to copy custom emojis. +- Allow higher resolution images. (4096x4096 instead of the previous limit of 1920x1080) +- Allow posting polls with only one poll option (if `MIN_POLL_OPTIONS` is set to 1 on your instance). +- Added oatstodon flavour (taken from [types.pl fork](https://github.com/ralsei/types.pl), by [@oat@hellsite.site](https://hellsite.site/@oat)) +- RSS feeds have titles again. + - Account RSS feeds show the CW (if applicable). + - Tag RSS feeds show the handle (username if local, username@domain if remote) and the CW (if applicable). -- You can view documentation for this project at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/). -- And contributing guidelines are available [here](CONTRIBUTING.md) and [here](https://glitch-soc.github.io/docs/contributing/). +## Previous differences now merged into glitch-soc +- Fixed incorrect upload size limit display when adding new a new custom emoji. ([Pull request](https://github.com/glitch-soc/mastodon/pull/1763)) +- Everything merged into vanilla Mastodon + +## Previous differences now merged into vanilla Mastodon +- The period of retention of IP addresses and sessions was made configurable. ([Pull request](https://github.com/mastodon/mastodon/pull/18757)) diff --git a/app/controllers/api/v1/custom_emojis_controller.rb b/app/controllers/api/v1/custom_emojis_controller.rb index 08b3474cc8..78b791a2a2 100644 --- a/app/controllers/api/v1/custom_emojis_controller.rb +++ b/app/controllers/api/v1/custom_emojis_controller.rb @@ -2,6 +2,7 @@ class Api::V1::CustomEmojisController < Api::BaseController skip_before_action :set_cache_headers + skip_before_action :require_authenticated_user!, unless: :whitelist_mode? def index expires_in 3.minutes, public: true diff --git a/app/controllers/api/v1/trends/statuses_controller.rb b/app/controllers/api/v1/trends/statuses_controller.rb index c275d5fc81..ef36f906d6 100644 --- a/app/controllers/api/v1/trends/statuses_controller.rb +++ b/app/controllers/api/v1/trends/statuses_controller.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true class Api::V1::Trends::StatusesController < Api::BaseController + before_action :require_user!, only: [:index], if: :require_auth? before_action :set_statuses after_action :insert_pagination_headers @@ -54,4 +55,8 @@ class Api::V1::Trends::StatusesController < Api::BaseController def records_continue? @statuses.size == limit_param(DEFAULT_STATUSES_LIMIT) end + + def require_auth? + !Setting.timeline_preview + end end diff --git a/app/javascript/flavours/glitch/actions/statuses.js b/app/javascript/flavours/glitch/actions/statuses.js index 5930b7a160..a3e2a24f28 100644 --- a/app/javascript/flavours/glitch/actions/statuses.js +++ b/app/javascript/flavours/glitch/actions/statuses.js @@ -34,6 +34,11 @@ export const STATUS_FETCH_SOURCE_REQUEST = 'STATUS_FETCH_SOURCE_REQUEST'; export const STATUS_FETCH_SOURCE_SUCCESS = 'STATUS_FETCH_SOURCE_SUCCESS'; export const STATUS_FETCH_SOURCE_FAIL = 'STATUS_FETCH_SOURCE_FAIL'; +export const STATUS_TRANSLATE_REQUEST = 'STATUS_TRANSLATE_REQUEST'; +export const STATUS_TRANSLATE_SUCCESS = 'STATUS_TRANSLATE_SUCCESS'; +export const STATUS_TRANSLATE_FAIL = 'STATUS_TRANSLATE_FAIL'; +export const STATUS_TRANSLATE_UNDO = 'STATUS_TRANSLATE_UNDO'; + export function fetchStatusRequest(id, skipLoading) { return { type: STATUS_FETCH_REQUEST, @@ -310,4 +315,36 @@ export function toggleStatusCollapse(id, isCollapsed) { id, isCollapsed, }; -} +}; + +export const translateStatus = id => (dispatch, getState) => { + dispatch(translateStatusRequest(id)); + + api(getState).post(`/api/v1/statuses/${id}/translate`).then(response => { + dispatch(translateStatusSuccess(id, response.data)); + }).catch(error => { + dispatch(translateStatusFail(id, error)); + }); +}; + +export const translateStatusRequest = id => ({ + type: STATUS_TRANSLATE_REQUEST, + id, +}); + +export const translateStatusSuccess = (id, translation) => ({ + type: STATUS_TRANSLATE_SUCCESS, + id, + translation, +}); + +export const translateStatusFail = (id, error) => ({ + type: STATUS_TRANSLATE_FAIL, + id, + error, +}); + +export const undoStatusTranslation = id => ({ + type: STATUS_TRANSLATE_UNDO, + id, +}); diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js index 95563503b2..3ef5f453fd 100644 --- a/app/javascript/flavours/glitch/components/status.js +++ b/app/javascript/flavours/glitch/components/status.js @@ -86,6 +86,7 @@ class Status extends ImmutablePureComponent { onEmbed: PropTypes.func, onHeightChange: PropTypes.func, onToggleHidden: PropTypes.func, + onTranslate: PropTypes.func, onInteractionModal: PropTypes.func, muted: PropTypes.bool, hidden: PropTypes.bool, @@ -476,6 +477,10 @@ class Status extends ImmutablePureComponent { this.node = c; } + handleTranslate = () => { + this.props.onTranslate(this.props.status); + } + renderLoadingMediaGallery () { return
; } @@ -793,6 +798,7 @@ class Status extends ImmutablePureComponent { mediaIcons={contentMediaIcons} expanded={isExpanded} onExpandedToggle={this.handleExpandedToggle} + onTranslate={this.handleTranslate} parseClick={parseClick} disabled={!router} tagLinks={settings.get('tag_misleading_links')} diff --git a/app/javascript/flavours/glitch/components/status_content.js b/app/javascript/flavours/glitch/components/status_content.js index c618cedcab..c59f42220c 100644 --- a/app/javascript/flavours/glitch/components/status_content.js +++ b/app/javascript/flavours/glitch/components/status_content.js @@ -1,11 +1,11 @@ import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; -import { FormattedMessage } from 'react-intl'; +import { FormattedMessage, injectIntl } from 'react-intl'; import Permalink from './permalink'; import classnames from 'classnames'; import Icon from 'flavours/glitch/components/icon'; -import { autoPlayGif } from 'flavours/glitch/initial_state'; +import { autoPlayGif, languages as preloadedLanguages, translationEnabled } from 'flavours/glitch/initial_state'; import { decode as decodeIDNA } from 'flavours/glitch/utils/idna'; const textMatchesTarget = (text, origin, host) => { @@ -62,13 +62,56 @@ const isLinkMisleading = (link) => { return !(textMatchesTarget(text, origin, host) || textMatchesTarget(text.toLowerCase(), origin, host)); }; -export default class StatusContent extends React.PureComponent { +class TranslateButton extends React.PureComponent { + + static propTypes = { + translation: ImmutablePropTypes.map, + onClick: PropTypes.func, + }; + + render () { + const { translation, onClick } = this.props; + + if (translation) { + const language = preloadedLanguages.find(lang => lang[0] === translation.get('detected_source_language')); + const languageName = language ? language[2] : translation.get('detected_source_language'); + const provider = translation.get('provider'); + + return ( +
+
+ +
+ + +
+ ); + } + + return ( + + ); + } + +} + +export default @injectIntl +class StatusContent extends React.PureComponent { + + static contextTypes = { + identity: PropTypes.object, + }; static propTypes = { status: ImmutablePropTypes.map.isRequired, expanded: PropTypes.bool, collapsed: PropTypes.bool, onExpandedToggle: PropTypes.func, + onTranslate: PropTypes.func, media: PropTypes.node, extraMedia: PropTypes.node, mediaIcons: PropTypes.arrayOf(PropTypes.string), @@ -77,6 +120,7 @@ export default class StatusContent extends React.PureComponent { onUpdate: PropTypes.func, tagLinks: PropTypes.bool, rewriteMentions: PropTypes.string, + intl: PropTypes.object, }; static defaultProps = { @@ -249,6 +293,10 @@ export default class StatusContent extends React.PureComponent { } } + handleTranslate = () => { + this.props.onTranslate(); + } + setContentsRef = (c) => { this.contentsNode = c; } @@ -263,18 +311,24 @@ export default class StatusContent extends React.PureComponent { disabled, tagLinks, rewriteMentions, + intl, } = this.props; const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden; + const renderTranslate = translationEnabled && this.context.identity.signedIn && this.props.onTranslate && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('contentHtml').length > 0 && status.get('language') !== null && intl.locale !== status.get('language'); - const content = { __html: status.get('contentHtml') }; + const content = { __html: status.get('translation') ? status.getIn(['translation', 'content']) : status.get('contentHtml') }; const spoilerContent = { __html: status.get('spoilerHtml') }; - const lang = status.get('language'); + const lang = status.get('translation') ? intl.locale : status.get('language'); const classNames = classnames('status__content', { 'status__content--with-action': parseClick && !disabled, 'status__content--with-spoiler': status.get('spoiler_text').length > 0, }); + const translateButton = renderTranslate && ( + + ); + if (status.get('spoiler_text').length > 0) { let mentionsPlaceholder = ''; @@ -350,11 +404,11 @@ export default class StatusContent extends React.PureComponent { onMouseLeave={this.handleMouseLeave} lang={lang} /> + {!hidden && translateButton} {media}
{extraMedia} - ); } else if (parseClick) { @@ -375,6 +429,7 @@ export default class StatusContent extends React.PureComponent { onMouseLeave={this.handleMouseLeave} lang={lang} /> + {translateButton} {media} {extraMedia} @@ -395,6 +450,7 @@ export default class StatusContent extends React.PureComponent { onMouseLeave={this.handleMouseLeave} lang={lang} /> + {translateButton} {media} {extraMedia} diff --git a/app/javascript/flavours/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js index 6cb5d5bce5..c2fd15b17c 100644 --- a/app/javascript/flavours/glitch/containers/status_container.js +++ b/app/javascript/flavours/glitch/containers/status_container.js @@ -24,7 +24,9 @@ import { deleteStatus, hideStatus, revealStatus, - editStatus + editStatus, + translateStatus, + undoStatusTranslation, } from 'flavours/glitch/actions/statuses'; import { initAddFilter, @@ -198,6 +200,14 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({ dispatch(editStatus(status.get('id'), history)); }, + onTranslate (status) { + if (status.get('translation')) { + dispatch(undoStatusTranslation(status.get('id'))); + } else { + dispatch(translateStatus(status.get('id'))); + } + }, + onDirect (account, router) { dispatch(directCompose(account, router)); }, diff --git a/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js b/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js index 61d38648ad..41eb6e90f0 100644 --- a/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js +++ b/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js @@ -392,8 +392,8 @@ class EmojiPickerDropdown extends React.PureComponent {
{button || 🙂}
diff --git a/app/javascript/flavours/glitch/features/compose/components/poll_form.js b/app/javascript/flavours/glitch/features/compose/components/poll_form.js index d5edccff33..0a52ecd310 100644 --- a/app/javascript/flavours/glitch/features/compose/components/poll_form.js +++ b/app/javascript/flavours/glitch/features/compose/components/poll_form.js @@ -81,7 +81,7 @@ class Option extends React.PureComponent {
- +
); diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js index f9d79013b5..cfa430e090 100644 --- a/app/javascript/flavours/glitch/features/getting_started/index.js +++ b/app/javascript/flavours/glitch/features/getting_started/index.js @@ -35,7 +35,6 @@ const messages = defineMessages({ follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' }, keyboard_shortcuts: { id: 'navigation_bar.keyboard_shortcuts', defaultMessage: 'Keyboard shortcuts' }, - lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' }, lists_subheading: { id: 'column_subheading.lists', defaultMessage: 'Lists' }, misc: { id: 'navigation_bar.misc', defaultMessage: 'Misc' }, menu: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, diff --git a/app/javascript/flavours/glitch/features/getting_started_misc/index.js b/app/javascript/flavours/glitch/features/getting_started_misc/index.js index de354d6b11..735116cfc3 100644 --- a/app/javascript/flavours/glitch/features/getting_started_misc/index.js +++ b/app/javascript/flavours/glitch/features/getting_started_misc/index.js @@ -19,7 +19,6 @@ const messages = defineMessages({ info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' }, show_me_around: { id: 'getting_started.onboarding', defaultMessage: 'Show me around' }, pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' }, - info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' }, keyboard_shortcuts: { id: 'navigation_bar.keyboard_shortcuts', defaultMessage: 'Keyboard shortcuts' }, featured_users: { id: 'navigation_bar.featured_users', defaultMessage: 'Featured users' }, }); diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js index d01eec811e..cc8e1f8f22 100644 --- a/app/javascript/flavours/glitch/features/local_settings/page/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js @@ -29,6 +29,7 @@ const messages = defineMessages({ rewrite_mentions_username: { id: 'settings.rewrite_mentions_username', defaultMessage: 'Rewrite with username' }, pop_in_left: { id: 'settings.pop_in_left', defaultMessage: 'Left' }, pop_in_right: { id: 'settings.pop_in_right', defaultMessage: 'Right' }, + enter_amount_prompt: { id: 'settings.enter_amount_prompt', defaultMessage: 'Enter an amount' }, }); export default @injectIntl diff --git a/app/javascript/flavours/glitch/features/local_settings/page/item/index.js b/app/javascript/flavours/glitch/features/local_settings/page/item/index.js index 6b24e41435..966fc5c1ee 100644 --- a/app/javascript/flavours/glitch/features/local_settings/page/item/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/page/item/index.js @@ -21,20 +21,21 @@ export default class LocalSettingsPageItem extends React.PureComponent { })), settings: ImmutablePropTypes.map.isRequired, placeholder: PropTypes.string, + number: PropTypes.bool, disabled: PropTypes.bool, }; handleChange = e => { const { target } = e; - const { item, onChange, options, placeholder } = this.props; + const { item, onChange, options, placeholder, number } = this.props; if (options && options.length > 0) onChange(item, target.value); - else if (placeholder) onChange(item, target.value); + else if (placeholder) onChange(item, number ? parseInt(target.value) : target.value); else onChange(item, target.checked); } render () { const { handleChange } = this; - const { settings, item, id, options, children, dependsOn, dependsOnNot, placeholder, disabled } = this.props; + const { settings, item, id, options, children, dependsOn, dependsOnNot, placeholder, number, disabled } = this.props; let enabled = !disabled; if (dependsOn) { @@ -76,7 +77,7 @@ export default class LocalSettingsPageItem extends React.PureComponent { ); - } else if (placeholder) { + } else if (placeholder || number) { return (
); } diff --git a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js index 3b46c6eec0..3a14bbca08 100644 --- a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js +++ b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js @@ -56,7 +56,7 @@ class NavigationPanel extends React.Component { )} {showTrends ? ( - + ) : ( )} diff --git a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js index 611fae1ced..a5364bebd8 100644 --- a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js @@ -144,10 +144,11 @@ const PageSix = ({ admin, domain }) => {

fork, + glitchsoc: Glitchsoc, Mastodon: Mastodon, github: GitHub, }} diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 72e13d9d68..bc2a2f1d6d 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -65,6 +65,7 @@ import Header from './components/header'; // Dummy import, to make sure that ends up in the application bundle. // Without this it ends up in ~8 very commonly used bundles. import '../../../glitch/components/status'; +import { timelinePreview } from 'flavours/glitch/initial_state'; const messages = defineMessages({ beforeUnload: { id: 'ui.beforeunload', defaultMessage: 'Your draft will be lost if you leave Mastodon.' }, @@ -75,7 +76,6 @@ const mapStateToProps = state => ({ hasComposingText: state.getIn(['compose', 'text']).trim().length !== 0, hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0, canUploadMore: !state.getIn(['compose', 'media_attachments']).some(x => ['audio', 'video'].includes(x.get('type'))) && state.getIn(['compose', 'media_attachments']).size < 4, - layout: state.getIn(['meta', 'layout']), layout_local_setting: state.getIn(['local_settings', 'layout']), isWide: state.getIn(['local_settings', 'stretch']), navbarUnder: state.getIn(['local_settings', 'navbar_under']), @@ -177,7 +177,7 @@ class SwitchingColumnsArea extends React.PureComponent { } } else if (singleUserMode && owner && initialState?.accounts[owner]) { redirect = ; - } else if (showTrends) { + } else if (showTrends && (signedIn || timelinePreview)) { redirect = ; } else { redirect = ; diff --git a/app/javascript/flavours/glitch/initial_state.js b/app/javascript/flavours/glitch/initial_state.js index a2058791f9..dcece01ffc 100644 --- a/app/javascript/flavours/glitch/initial_state.js +++ b/app/javascript/flavours/glitch/initial_state.js @@ -81,6 +81,7 @@ * @property {boolean=} use_pending_items * @property {string} version * @property {number} visible_reactions + * @property {boolean} translation_enabled * @property {object} local_settings */ @@ -125,6 +126,7 @@ export const mascot = getMeta('mascot'); export const maxReactions = (initialState && initialState.max_reactions) || 1; export const me = getMeta('me'); export const movedToAccountId = getMeta('moved_to_account_id'); +export const visibleReactions = getMeta('visible_reactions'); export const owner = getMeta('owner'); export const profile_directory = getMeta('profile_directory'); export const reduceMotion = getMeta('reduce_motion'); @@ -141,6 +143,7 @@ export const useBlurhash = getMeta('use_blurhash'); export const usePendingItems = getMeta('use_pending_items'); export const version = getMeta('version'); export const visibleReactions = getMeta('visible_reactions'); +export const translationEnabled = getMeta('translation_enabled'); export const languages = initialState?.languages; // Glitch-soc-specific settings diff --git a/app/javascript/flavours/glitch/locales/de.js b/app/javascript/flavours/glitch/locales/de.js index a4daa59495..97db3f7ab4 100644 --- a/app/javascript/flavours/glitch/locales/de.js +++ b/app/javascript/flavours/glitch/locales/de.js @@ -1,6 +1,9 @@ import inherited from 'mastodon/locales/de.json'; const messages = { + 'getting_started.open_source_notice': 'Catstodon ist quelloffene Software, zudem ein Fork von {glitchsoc}, was wiederum ein Fork von {Mastodon} ist. Du kannst auf GitHub unter {github} dazu beitragen oder Probleme melden.', + 'onboarding.page_six.github': '{domain} läuft auf Catstodon, was ein Fork ({fork}) von {glitchsoc} ist, welches wiederum ein Fork ({fork}) von {Mastodon} ist. It is fully compatible with all Mastodon apps and instances. Catstodon ist quelloffene Software. Du kannst auf GitHub unter {github} Probleme melden, nach neuen Funktionen fragen oder zum Code beitragen.', + 'notification.reaction': '{name} hat auf deinen Beitrag reagiert', 'notifications.column_settings.reaction': 'Reaktionen:', diff --git a/app/javascript/flavours/glitch/locales/en.js b/app/javascript/flavours/glitch/locales/en.js index 7065cbe262..9e7f37012d 100644 --- a/app/javascript/flavours/glitch/locales/en.js +++ b/app/javascript/flavours/glitch/locales/en.js @@ -1,7 +1,7 @@ import inherited from 'mastodon/locales/en.json'; const messages = { - 'getting_started.open_source_notice': 'Glitchsoc is free open source software forked from {Mastodon}. You can contribute or report issues on GitHub at {github}.', + 'getting_started.open_source_notice': 'Catstodon is open source software, a friendly fork of {glitchsoc}, which in turn is a fork of {Mastodon}. You can contribute or report issues on GitHub at {github}.', 'layout.auto': 'Auto', 'layout.current_is': 'Your current layout is:', 'layout.desktop': 'Desktop', @@ -10,7 +10,7 @@ const messages = { 'getting_started.onboarding': 'Show me around', 'onboarding.page_one.federation': '{domain} is an \'instance\' of Mastodon. Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.', 'onboarding.page_one.welcome': 'Welcome to {domain}!', - 'onboarding.page_six.github': '{domain} runs on Glitchsoc. Glitchsoc is a friendly {fork} of {Mastodon}, and is compatible with any Mastodon instance or app. Glitchsoc is entirely free and open-source. You can report bugs, request features, or contribute to the code on {github}.', + 'onboarding.page_six.github': '{domain} runs on Catstodon, which is a {fork} of {glitchsoc}, which, in turn, is a friendly {fork} of {Mastodon}. It is fully compatible with all Mastodon apps and instances. Catstodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.', 'settings.auto_collapse': 'Automatic collapsing', 'settings.auto_collapse_all': 'Everything', 'settings.auto_collapse_lengthy': 'Lengthy toots', diff --git a/app/javascript/flavours/glitch/locales/es.js b/app/javascript/flavours/glitch/locales/es.js index f22062977c..72a2ba04f3 100644 --- a/app/javascript/flavours/glitch/locales/es.js +++ b/app/javascript/flavours/glitch/locales/es.js @@ -13,7 +13,6 @@ const messages = { 'compose.attach': 'Adjuntar...', 'favourite_modal.combo': 'Puedes presionar {combo} para omitir esto la próxima vez', 'getting_started.onboarding': 'Paseo inicial', - 'getting_started.open_source_notice': 'Glitchsoc es software libre y gratuito bifurcado de {Mastodon}. Puedes contribuir o reportar errores en GitHub en {github}.', 'home.column_settings.show_direct': 'Mostrar mensajes directos', 'layout.auto': 'Automático', 'layout.current_is': 'Tu diseño actual es:', @@ -34,7 +33,6 @@ const messages = { 'notifications.marked_clear': 'Limpiar notificaciones seleccionadas', 'onboarding.page_one.federation': '{domain} es una "instancia" de Mastodon. Mastodon es una red de servidores independientes que se unen para crear una red social más grande. A estos servidores los llamamos instancias.', 'onboarding.page_one.welcome': '¡Bienvenidx a {domain}!', - 'onboarding.page_six.github': '{domain} usa Glitchsoc. Glitchsoc es una bifurcación {fork} amigable de {Mastodon}, y es compatible con cualquier instancia o aplicación de Mastodon. Glitchsoc es completamente gratuito y de código abierto. Puedes reportar errores, solicitar funciones o contribuir al código en {github}.', 'settings.always_show_spoilers_field': 'Siempre mostrar el campo de advertencia de contenido', 'settings.auto_collapse_all': 'Todo', 'settings.auto_collapse_lengthy': 'Toots largos', diff --git a/app/javascript/flavours/glitch/locales/ja.js b/app/javascript/flavours/glitch/locales/ja.js index 52aeed3d69..c0e75a2220 100644 --- a/app/javascript/flavours/glitch/locales/ja.js +++ b/app/javascript/flavours/glitch/locales/ja.js @@ -1,7 +1,6 @@ import inherited from 'mastodon/locales/ja.json'; const messages = { - 'getting_started.open_source_notice': 'Glitchsocは{Mastodon}によるフリーなオープンソースソフトウェアです。誰でもGitHub({github})から開発に參加したり、問題を報告したりできます。', 'layout.auto': '自動', 'layout.current_is': 'あなたの現在のレイアウト:', 'layout.desktop': 'デスクトップ', @@ -12,7 +11,6 @@ const messages = { 'getting_started.onboarding': '解説を表示', 'onboarding.page_one.federation': '{domain}はMastodonのインスタンスです。Mastodonとは、独立したサーバが連携して作るソーシャルネットワークです。これらのサーバーをインスタンスと呼びます。', 'onboarding.page_one.welcome': '{domain}へようこそ!', - 'onboarding.page_six.github': '{domain}はGlitchsocを使用しています。Glitchsocは{Mastodon}のフレンドリーな{fork}で、どんなMastodonアプリやインスタンスとも互換性があります。Glitchsocは完全に無料で、オープンソースです。{github}でバグ報告や機能要望あるいは貢獻をすることが可能です。', 'settings.always_show_spoilers_field': '常にコンテンツワーニング設定を表示する(指定がない場合は通常投稿)', 'settings.auto_collapse': '自動折りたたみ', 'settings.auto_collapse_all': 'すべて', diff --git a/app/javascript/flavours/glitch/locales/ko.js b/app/javascript/flavours/glitch/locales/ko.js index a817044c1b..1c876483e3 100644 --- a/app/javascript/flavours/glitch/locales/ko.js +++ b/app/javascript/flavours/glitch/locales/ko.js @@ -52,7 +52,6 @@ const messages = { 'endorsed_accounts_editor.endorsed_accounts': '추천하는 계정들', 'favourite_modal.combo': '다음엔 {combo}를 눌러 건너뛸 수 있습니다', 'getting_started.onboarding': '둘러보기', - 'getting_started.open_source_notice': '글리치는 {Mastodon}의 자유 오픈소스 포크버전입니다. {github}에서 문제를 리포팅 하거나 기여를 할 수 있습니다.', 'home.column_settings.advanced': '고급', 'home.column_settings.filter_regex': '정규표현식으로 필터', 'home.column_settings.show_direct': 'DM 보여주기', @@ -93,7 +92,6 @@ const messages = { 'onboarding.page_six.almost_done': '거의 다 되었습니다…', 'onboarding.page_six.appetoot': '본 아페툿!', 'onboarding.page_six.apps_available': 'iOS, 안드로이드, 그리고 다른 플랫폼들을 위한 {apps}이 존재합니다.', - 'onboarding.page_six.github': '{domain}은 글리치를 통해 구동 됩니다. 글리치는 {Mastodon}의 {fork}입니다, 그리고 어떤 마스토돈 인스턴스나 앱과도 호환 됩니다. 글리치는 완전한 자유 오픈소스입니다. {github}에서 버그를 리포팅 하거나, 기능을 제안하거나, 코드를 기여할 수 있습니다.', 'onboarding.page_six.guidelines': '커뮤니티 가이드라인', 'onboarding.page_six.read_guidelines': '{domain}의 {guidelines}을 읽어주세요!', 'onboarding.page_six.various_app': '모바일 앱', diff --git a/app/javascript/flavours/glitch/locales/pl.js b/app/javascript/flavours/glitch/locales/pl.js index f430bf5770..3808997833 100644 --- a/app/javascript/flavours/glitch/locales/pl.js +++ b/app/javascript/flavours/glitch/locales/pl.js @@ -1,7 +1,6 @@ import inherited from 'mastodon/locales/pl.json'; const messages = { - 'getting_started.open_source_notice': 'Glitchsoc jest wolnym i otwartoźródłowym forkiem oprogramowania {Mastodon}. Możesz współtworzyć projekt lub zgłaszać błędy na GitHubie pod adresem {github}.', 'layout.auto': 'Automatyczny', 'layout.current_is': 'Twój obecny układ to:', 'layout.desktop': 'Desktopowy', @@ -11,7 +10,6 @@ const messages = { 'getting_started.onboarding': 'Rozejrzyj się', 'onboarding.page_one.federation': '{domain} jest \'instancją\' Mastodona. Mastodon to sieć działających niezależnie serwerów tworzących jedną sieć społecznościową. Te serwery nazywane są instancjami.', 'onboarding.page_one.welcome': 'Witamy na {domain}!', - 'onboarding.page_six.github': '{domain} jest oparty na Glitchsoc. Glitchsoc jest {forkiem} {Mastodon}a kompatybilnym z każdym klientem i aplikacją Mastodona. Glitchsoc jest całkowicie wolnym i otwartoźródłowym oprogramowaniem. Możesz zgłaszać błędy i sugestie funkcji oraz współtworzyć projekt na {github}.', 'settings.auto_collapse': 'Automatyczne zwijanie', 'settings.auto_collapse_all': 'Wszystko', 'settings.auto_collapse_lengthy': 'Długie wpisy', diff --git a/app/javascript/flavours/glitch/locales/zh-CN.js b/app/javascript/flavours/glitch/locales/zh-CN.js index 21a68fc01b..7b754ebcec 100644 --- a/app/javascript/flavours/glitch/locales/zh-CN.js +++ b/app/javascript/flavours/glitch/locales/zh-CN.js @@ -53,7 +53,6 @@ const messages = { 'endorsed_accounts_editor.endorsed_accounts': '推荐用户', 'favourite_modal.combo': '下次你可以按 {combo} 跳过这个', 'getting_started.onboarding': '参观一下', - 'getting_started.open_source_notice': 'Glitchsoc 是由 {Mastodon} 分叉出来的免费开源软件。你可以在 GitHub 上贡献或报告问题,地址是 {github}。', 'home.column_settings.advanced': '高级', 'home.column_settings.filter_regex': '按正则表达式过滤', 'home.column_settings.show_direct': '显示私信', @@ -94,7 +93,6 @@ const messages = { 'onboarding.page_six.almost_done': '就快完成了...', 'onboarding.page_six.appetoot': '尽情享用吧!', 'onboarding.page_six.apps_available': '有适用于 iOS、Android 和其他平台的应用程序。', - 'onboarding.page_six.github': '{domain} 在 Glitchsoc 上运行。Glitchsoc 是 {Mastodon} 的一个友好 {fork},与任何 Mastodon 实例或应用兼容。Glitchsoc 是完全免费和开源的。你可以在 {github} 上报告错误、请求功能或贡献代码。', 'onboarding.page_six.guidelines': '社区准则', 'onboarding.page_six.read_guidelines': '请阅读 {domain} 的 {guidelines}!', 'onboarding.page_six.various_app': '应用程序', @@ -198,4 +196,4 @@ const messages = { 'web_app_crash.title': '抱歉,Mastodon 出了点问题。', }; -export default Object.assign({}, inherited, messages); \ No newline at end of file +export default Object.assign({}, inherited, messages); diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js index b1c792406c..0fe0cc55eb 100644 --- a/app/javascript/flavours/glitch/reducers/compose.js +++ b/app/javascript/flavours/glitch/reducers/compose.js @@ -60,6 +60,7 @@ import { me, defaultContentType } from 'flavours/glitch/initial_state'; import { overwrite } from 'flavours/glitch/utils/js_helpers'; import { unescapeHTML } from 'flavours/glitch/utils/html'; import { recoverHashtags } from 'flavours/glitch/utils/hashtag'; +import { pollLimits } from 'flavours/glitch/initial_state'; const totalElefriends = 3; @@ -127,7 +128,7 @@ const initialState = ImmutableMap({ }); const initialPoll = ImmutableMap({ - options: ImmutableList(['', '']), + options: ImmutableList(new Array(pollLimits.min_options).fill('')), expires_in: 24 * 3600, multiple: false, }); diff --git a/app/javascript/flavours/glitch/reducers/statuses.js b/app/javascript/flavours/glitch/reducers/statuses.js index 258a5aaa60..22fdeb2841 100644 --- a/app/javascript/flavours/glitch/reducers/statuses.js +++ b/app/javascript/flavours/glitch/reducers/statuses.js @@ -18,6 +18,8 @@ import { STATUS_REVEAL, STATUS_HIDE, STATUS_COLLAPSE, + STATUS_TRANSLATE_SUCCESS, + STATUS_TRANSLATE_UNDO, STATUS_FETCH_REQUEST, STATUS_FETCH_FAIL, } from 'flavours/glitch/actions/statuses'; @@ -129,6 +131,10 @@ export default function statuses(state = initialState, action) { return state.setIn([action.id, 'collapsed'], action.isCollapsed); case TIMELINE_DELETE: return deleteStatus(state, action.id, action.references); + case STATUS_TRANSLATE_SUCCESS: + return state.setIn([action.id, 'translation'], fromJS(action.translation)); + case STATUS_TRANSLATE_UNDO: + return state.deleteIn([action.id, 'translation']); default: return state; } diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 80b0598a50..84aca2ebc0 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -15,7 +15,7 @@ display: block; font-size: 15px; line-height: 20px; - color: $ui-highlight-color; + color: $highlight-text-color; border: 0; background: transparent; padding: 0; diff --git a/app/javascript/flavours/glitch/styles/components/status.scss b/app/javascript/flavours/glitch/styles/components/status.scss index 31a03d45ec..c746a0bb1f 100644 --- a/app/javascript/flavours/glitch/styles/components/status.scss +++ b/app/javascript/flavours/glitch/styles/components/status.scss @@ -206,15 +206,13 @@ } } -.status__content__edited-label { - display: block; - cursor: default; +.translate-button { + margin-top: 16px; font-size: 15px; line-height: 20px; - padding: 0; - padding-top: 8px; + display: flex; + justify-content: space-between; color: $dark-text-color; - font-weight: 500; } .status__content__spoiler-link { diff --git a/app/javascript/flavours/glitch/styles/homogay.scss b/app/javascript/flavours/glitch/styles/homogay.scss new file mode 100644 index 0000000000..481c6492ee --- /dev/null +++ b/app/javascript/flavours/glitch/styles/homogay.scss @@ -0,0 +1,4 @@ +@import 'homogay/variables'; +@import 'index'; +@import 'homogay/diff'; + diff --git a/app/javascript/flavours/glitch/styles/homogay/animations.scss b/app/javascript/flavours/glitch/styles/homogay/animations.scss new file mode 100644 index 0000000000..06ca5bb7ba --- /dev/null +++ b/app/javascript/flavours/glitch/styles/homogay/animations.scss @@ -0,0 +1,109 @@ +// turn the timed line into a highly addictive dopamine slot machine + +// fav button +.no-reduce-motion .icon-button.star-icon { + &.deactivate { + & > .fa-star { + animation: none; + } + } + &.activate { + & > .fa-star { + animation: spring-rotate-in 1s cubic-bezier(.2, 0, .4, 1); + } + } +} +@keyframes spring-rotate-in { + 0% { + transform: rotate(0deg); + } + 20% { + transform: rotate(20deg); + } + 60% { + transform: rotate(-380deg); + } + 85% { + transform: rotate(-355deg); + } + 100% { + transform: rotate(-360deg); + } +} +@keyframes spring-rotate-out { + 0% { + transform: rotate(-360deg); + } + 60% { + transform: rotate(20deg); + } + 85% { + transform: rotate(-5deg); + } + 100% { + transform: rotate(0deg); + } +} + +// bookmark button +.no-reduce-motion .icon-button { + & > .fa-bookmark { + transform: translateY(0); + animation: none; + } + &.active > .fa-bookmark { + animation: bookmark-save .6s cubic-bezier(.2, 0, .4, 1); + } +} +@keyframes bookmark-save { + 0% { + transform: translateY(0); + } + 40% { + transform: translateY(-3px); + } + 60% { + transform: translateY(4px); + } + 100% { + transform: translateY(0); + } +} + +// collapse button at the top right of all posts +.no-reduce-motion .status__collapse-button { + &.activate > .fa-angle-double-up { + animation: spring-flip-in .5s cubic-bezier(.2, 0, .4, 1); + } + &.deactivate > .fa-angle-double-up { + animation: spring-flip-out .5s cubic-bezier(.2, 0, .4, 1); + } +} +@keyframes spring-flip-in { + 0% { + transform: rotate(0deg); + } + 60% { + transform: rotate(-190deg); + } + 85% { + transform: rotate(-175deg); + } + 100% { + transform: rotate(-180deg); + } +} +@keyframes spring-flip-out { + 0% { + transform: rotate(-180deg); + } + 60% { + transform: rotate(10deg); + } + 85% { + transform: rotate(-5deg) + } + 100% { + transform: rotate(0deg); + } +} diff --git a/app/javascript/flavours/glitch/styles/homogay/diff.scss b/app/javascript/flavours/glitch/styles/homogay/diff.scss new file mode 100644 index 0000000000..667cf6ed8e --- /dev/null +++ b/app/javascript/flavours/glitch/styles/homogay/diff.scss @@ -0,0 +1,161 @@ +body { + background: darken($ui-base-color, 5%); +} + +// hashtags in primary color +.status__content a { + color: $highlight-text-color; +} + +// compose panel +.compose-panel .autosuggest-textarea label .autosuggest-textarea__textarea, +.compose-form .autosuggest-input label .autosuggest-textarea__textarea, +.compose-form__buttons-wrapper, +.compose-form__warning, +.spoiler-input input, +.compose-form__modifiers, +.reply-indicator { + background: lighten($ui-base-color, 4%); + color: $primary-text-color; +} +.compose-form .autosuggest-textarea label .autosuggest-textarea__textarea { + border-top-left-radius: $border-radius; + border-top-right-radius: $border-radius; +} +.compose-form__buttons-wrapper { + border-bottom-left-radius: $border-radius; + border-bottom-right-radius: $border-radius; +} +.compose-panel .compose-form__autosuggest-wrapper { + background-color: #fff0; // transparent background so it doesn't mess with border-radius +} +.poll__option input[type="text"], +.compose-form__poll-wrapper select { + border-color: $ui-base-lighter-color; +} +.autosuggest-textarea__suggestions { + background: lighten($ui-base-color, 4%); +} +.autosuggest-textarea__suggestions__item.selected, +.autosuggest-textarea__suggestions__item:hover { + background: $ui-highlight-color; +} + +.emoji-mart-bar:first-child { + background: lighten($ui-base-color, 7%); + border-bottom-color: #fff0; + border-top-left-radius: $border-radius; + border-top-right-radius: $border-radius; +} +.emoji-mart-anchor:not(.emoji-mart-anchor-selected) { + color: $ui-base-lighter-color; +} + +.search__input { + background: lighten($ui-base-color, 4%); +} + +// dropdowns +.dropdown-menu, +.dropdown-menu__item a, +.dropdown-menu__item button { + background: $ui-base-lighter-color; +} +.dropdown-menu__arrow.top { + border-top-color: $ui-base-lighter-color; +} +.dropdown-menu__arrow.bottom { + border-bottom-color: $ui-base-lighter-color; +} + +// general modals +.modal-root__modal { + background: $ui-base-color; +} +.report-modal__container { + border-top-color: $ui-base-lighter-color; +} +.report-modal__comment { + border-right-color: $ui-base-lighter-color; +} +.report-modal__comment .setting-text { + background: $ui-base-color; +} +.boost-modal__action-bar, +.doodle-modal__action-bar, +.confirmation-modal__action-bar, +.mute-modal__action-bar, +.block-modal__action-bar { + background: lighten($ui-base-color, 5%); +} +.confirmation-modal__secondary-button, +.confirmation-modal__cancel-button, +.mute-modal__cancel-button, +.block-modal__cancel-button { + color: $primary-text-color; + &:hover { + color: $ui-highlight-color; + } +} + +// app settings modal +.glitch.local-settings { + background: $ui-base-color; +} +.glitch.local-settings__navigation, +.glitch.local-settings__navigation__item { + background: lighten($ui-base-color, 4%); +} +.glitch.local-settings__navigation__item { + border-bottom-color: $ui-base-lighter-color; +} + +// border radius +.button, +.dropdown-menu, +.account__avatar, +.search__input, +.spoiler-input input, +.status-card, +.language-dropdown__dropdown, +.privacy-dropdown__dropdown, +.poll__option input[type="text"], +.compose-form__poll-wrapper select, +.account__header__tabs__buttons .icon-button, +.emoji-picker-dropdown__menu, +.emoji-mart-search input, +.boost-modal, +.report-modal, +.block-modal, +.confirmation-modal, +.actions-modal, +.mute-modal, +.compare-history-modal { + border-radius: $border-radius; +} +.dropdown-menu { + padding-top: $border-radius; + padding-bottom: $border-radius; +} +.emoji-mart-scroll { + margin-bottom: $border-radius; + padding-bottom: 0; +} +.column-header { + border-top-left-radius: $border-radius; + border-top-right-radius: $border-radius; +} +.column > .scrollable { + border-bottom-left-radius: $border-radius; + border-bottom-right-radius: $border-radius; +} + +// timed line +.status { + border-bottom: 0; // no separators between posts +} +.media-gallery__item.letterbox { + background: none; // remove the black background from letterbox images +} + +@import 'animations'; diff --git a/app/javascript/flavours/glitch/styles/homogay/variables.scss b/app/javascript/flavours/glitch/styles/homogay/variables.scss new file mode 100644 index 0000000000..db695529d6 --- /dev/null +++ b/app/javascript/flavours/glitch/styles/homogay/variables.scss @@ -0,0 +1,53 @@ +// Commonly used web colors +$black: #000000; +$white: #ffffff; +$success-green: #5fe43d; +$error-red: #c9343b; +$warning-red: #c96932; +$gold-star: #e4ba3d; + +$red-bookmark: $success-green; + +// Values from the classic Mastodon UI +$classic-base-color: #150f21; +$classic-primary-color: #d4b6cb; +$classic-secondary-color: #eaddf4; +$classic-highlight-color: #de18a3; + +// Variables for defaults in UI +$base-shadow-color: $black !default; +$base-overlay-background: $black !default; +$base-border-color: $white !default; +$simple-background-color: lighten($classic-base-color, 7%) !default; +$valid-value-color: $success-green !default; +$error-value-color: $error-red !default; + +// Tell UI to use selected colors +$ui-base-color: $classic-base-color !default; +$ui-base-lighter-color: #5f4a6e !default; +$ui-primary-color: $classic-primary-color !default; +$ui-secondary-color: $classic-secondary-color !default; +$ui-highlight-color: $classic-highlight-color !default; + +// Variables for texts +$primary-text-color: $classic-secondary-color !default; +$darker-text-color: $ui-primary-color !default; +$dark-text-color: $ui-base-lighter-color !default; +$secondary-text-color: $ui-secondary-color !default; +$highlight-text-color: lighten($ui-highlight-color, 8%) !default; +$action-button-color: $ui-base-lighter-color !default; +$passive-text-color: $gold-star !default; +$active-passive-text-color: $success-green !default; + +// For texts on inverted backgrounds +$inverted-text-color: $primary-text-color !default; // we don't do inverted backgrounds +$lighter-text-color: $ui-base-lighter-color !default; +$light-text-color: $ui-primary-color !default; + +// Variables for components +$media-modal-media-max-width: 100%; + +// put margins on top and bottom of image to avoid the screen covered by image. +$media-modal-media-max-height: 80%; + +$border-radius: 8px; diff --git a/app/javascript/flavours/glitch/styles/oatstodon.scss b/app/javascript/flavours/glitch/styles/oatstodon.scss new file mode 100644 index 0000000000..c630bad7c1 --- /dev/null +++ b/app/javascript/flavours/glitch/styles/oatstodon.scss @@ -0,0 +1,332 @@ +@import 'index'; + +/* customize ya stuff */ +:root { + --border-radius: 5px; + + /* rgb for transparency to work */ + --text-color: 217, 225, 232; + --text-color-secondary: 96, 105, 132; /* less bright, for unimportant bits */ + + --background-color: 18, 18, 37; + --background-color-brighter: 22, 22, 47; + --app-background-color: 8, 8, 17; /* used only for the VERY background in the back */ + + --accent-color: 39, 183, 145; + --accent-color-secondary: 62, 91, 84; /* less saturated ver of --accent-color */ + --accent-color-bright: 92, 193, 162; +} + +.account__avatar-overlay-base, .account__avatar-overlay-overlay, .account__avatar { + border-radius: var(--border-radius); +} + +/* roundening shenanigans */ + +.drawer > div, nav, .search, .drawer__header a, .drawer--header a, .search__input { + border-radius: var(--border-radius) !important; +} + +.column-header, .column-back-button, .navigation-panel .column-link:nth-child(1), .navigation-panel .column-link:nth-child(10), .navigation-bar { + border-radius: var(--border-radius) var(--border-radius) 0px 0px; +} +.column > .scrollable, .getting-started, .navigation-panel .column-link:nth-child(8), .navigation-panel .column-link:nth-child(11) { + border-radius: 0px 0px var(--border-radius) var(--border-radius); +} + +/* standard fg/bg color changes */ + +.drawer__inner, .drawer__inner__mastodon, .drawer__header, .drawer--header, .actions-modal, .block-modal, .boost-modal, .confirmation-modal, .mute-modal, .report-modal, article, .getting-started, .column-subheading, .column-link, .column-subheading, .column-link, .emoji-mart-scroll, .emoji-mart-search, .emoji-mart-category-label > span, .emoji-picker-dropdown__menu, .scrollable, .empty-column-indicator, .column-inline-form, .dropdown-menu, .dropdown-menu__item a, .account__header__fields dt, .search-popout, .confirmation-modal__action-bar, .reactions-bar__item, .emoji-picker-dropdown__modifiers__menu, .content-wrapper, .sidebar-wrapper--empty, .regeneration-indicator, .tabs-bar, .navigation-bar, .trends__header, .modal-layout { + background-color: rgb(var(--background-color)) !important; + color: rgb(var(--text-color)) !important; +} +.glitch.local-settings__navigation, .glitch.local-settings__navigation__item, .glitch.local-settings__page, .glitch.local-settings { + background-color: rgb(var(--background-color)); + color: rgb(var(--text-color)); +} + +.modal-layout, .modal-layout__mastodon > * { + background-image: none; +} + +.account__section-headline a.active::after, .account__section-headline button.active::after, .notification__filter-bar a.active::after, .notification__filter-bar button.active::after, .account__section-headline a.active::after, .account__section-headline a.active::before, .account__section-headline button.active::after, .account__section-headline button.active::before, .notification__filter-bar a.active::after, .notification__filter-bar a.active::before, .notification__filter-bar button.active::after, .notification__filter-bar button.active::before { + border-color: transparent transparent rgb(var(--background-color)); +} + +.dropdown-menu__arrow { + border-bottom-color: rgb(var(--background-color)) !important; +} +.dropdown-menu__arrow.top { + border-top-color: rgb(var(--background-color)) !important; +} + +.reply-indicator__content, .status__content, .reply-indicator__display-name, .privacy-dropdown__option__icon, .composer--options--dropdown--content--item .icon, .composer--reply > .content { + color: rgb(var(--text-color)) !important; +} + +html { + scrollbar-color: rgb(var(--background-color-brighter)) rgba(0,0,0,0.1); +} + +.tabs-bar__wrapper { + background: rgb(var(--app-background-color)); +} + +.column-header, .column-header__button, .account__section-headline, .notification__filter-bar > button, .emoji-mart-bar, .column-back-button, .column-header__back-button, .announcements, .column-header__collapsible-inner, .status.status-direct:not(.read), .notification__filter-bar, .glitch.local-settings__page { + background-color: rgb(var(--background-color-brighter)) !important; + border-bottom: none; +} + +.reply-indicator, .emoji-picker-dropdown__modifiers__menu button:hover, .compose-form .compose-form__buttons-wrapper, .composer--options-wrapper, .compose-form__poll-wrapper select, .flash-message, .card__bar, .card > a:hover .card__bar, .glitch.local-settings__navigation__item:hover { + background-color: rgb(var(--background-color-brighter)); +} + +.columns-area, .app-body, .getting-started__wrapper { + background-color: rgb(var(--app-background-color)); +} + +.privacy-dropdown__option__content strong, .composer--options--dropdown--content strong, .character-counter, .report-modal__comment .setting-text-label, .compose-form__poll-wrapper select { + color: rgb(var(--text-color)) !important; +} + +input, textarea, .compose-form__modifiers, .privacy-dropdown__dropdown, .composer--options--dropdown--content, .privacy-dropdown__value { + background-color: rgb(var(--background-color-brighter)) !important; + color: rgb(var(--text-color)) !important; +} + +.compose-form__buttons-wrapper, .admin-wrapper .sidebar-wrapper__inner, .admin-wrapper .sidebar ul a:hover, .admin-wrapper .sidebar ul a, .admin-wrapper .sidebar ul a.selected, .account__disclaimer, .account__action-bar-links { + background-color: rgb(var(--background-color-brighter)); +} + +.detailed-status, .detailed-status__action-bar, .account__header__bar, .focusable:focus { + background-color: rgb(var(--background-color-brighter)) !important; + border-bottom: none; + border-top: none; +} + +.status.collapsed .status__content::after { + background: linear-gradient(rgba(var(--background-color),0), rgba(var(--background-color),0)) !important; +} + +/* accent color changes */ + +.button, .react-toggle--checked .react-toggle-track, .react-toggle--checked:hover .react-toggle-track, .react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track, .button.logo-button, .emoji-mart-anchor-bar, .loading-bar, .icon-with-badge__badge, .video-player__volume__current, .video-player__volume__handle, .upload-progress__tracker, .video-player__seek__buffer, .video-player__seek__progress, .floating-action-button { + background-color: rgb(var(--accent-color)); +} +.react-toggle--checked .react-toggle-thumb, .compose-form__sensitive-button .checkbox, .filters .filter-subset a.selected, .account__action-bar__tab.active, .tabs-bar__link.active, .notification.unread::before, .status.unread::before { + border-color: rgb(var(--accent-color)); +} + +.text-icon-button, .icon-button.inverted, button.inverted:hover, .icon-button, .icon-button:hover, .status__action-bar__counter__label, .text-icon-button:active, .text-icon-button:focus, .text-icon-button:hover, .icon-button.disabled, .composer--options--dropdown.open > .value { + color: rgb(var(--accent-color-secondary)); +} +.status__info__icons i { + color: rgb(var(--accent-color-secondary)) !important; +} + +.status__content__spoiler-link { + background-color: rgb(var(--accent-color-secondary)) !important; +} +.column-header__wrapper.active::before { + background: radial-gradient(ellipse, rgba(var(--accent-color),.23) 0%, rgba(var(--accent-color),0) 60%); +} +.column-header__wrapper.active { + box-shadow: 0 1px 0 rgba(var(--accent-color),.3); +} + +.compose-form__sensitive-button .checkbox.active, .poll__chart.leading { + border-color: rgb(var(--accent-color)); + background-color: rgb(var(--accent-color)); +} + +.poll__chart { + background-color: rgb(var(--accent-color-secondary)); +} + +.column-header.active .column-header__icon { + text-shadow: 0 0 10px rgba(var(--accent-color),.4); +} + +.text-icon-button:active, .text-icon-button:focus, .text-icon-button:hover, .drawer__header a:hover, .drawer--header a:hover, .drawer--header a:focus, .icon-button:hover, .reactions-bar__item:hover { + background-color: rgba(var(--accent-color-secondary), .1); +} + +.icon-button.inverted:active, .icon-button.inverted:focus, .icon-button.inverted:hover, .reactions-bar__item.active { + background-color: rgba(var(--accent-color-secondary), .25); + color: rgb(var(--accent-color-secondary)); +} + +.button:active, .button:focus, .button:hover, .admin-wrapper .sidebar ul .simple-navigation-active-leaf a:hover, .simple_form .block-button:hover, .simple_form .button:hover, .simple_form button:hover, .button.logo-button:active, .button.logo-button:focus, .button.logo-button:hover, .floating-action-button:hover, .glitch.local-settings__navigation__item.active:hover { + background-color: rgb(var(--accent-color-bright)); +} + +.privacy-dropdown__option.active, .composer--options--dropdown--content--item.active, .privacy-dropdown__option:hover, .composer--options--dropdown--content--item:hover, .privacy-dropdown__option.active:hover, .composer--options--dropdown--content.active:hover, .admin-wrapper .sidebar ul .simple-navigation-active-leaf a, .simple_form .block-button, .simple_form .button, .simple_form button, .simple_form .block-button:active, .simple_form .block-button:focus, .simple_form .button:active, .simple_form .button:focus, .simple_form button:active, .simple_form button:focus, .composer--options--dropdown.open > .value, .glitch.local-settings__navigation__item.active { + background-color: rgb(var(--accent-color)); +} + +.status__info__icons .icon-button.active i, .tabs-bar__link.active, .status__content a { + color: rgb(var(--accent-color)) !important; +} + + +.trends__item__sparkline path:last-child { + stroke: rgb(var(--accent-color)) !important; +} +.trends__item__sparkline path:first-child { + fill: rgb(var(--accent-color-secondary)) !important; +} + +a.u-url, .status-link, .column-header__back-button, .status__content__read-more-button, .column-header.active .column-header__icon, .column-link.active, .account__section-headline a.active, .account__section-headline button.active, .notification__filter-bar a.active, .notification__filter-bar button.active, .account__header__content a, .account__header__bio .account__header__fields a, .reactions-bar__item.active .reactions-bar__item__count, .emoji-mart-anchor-selected, .reply-indicator__content a, .compose-form .compose-form__warning a, .text-icon-button.active, .icon-button.inverted.active, .drawer__tab:hover, .icon-button.active, .column-back-button, .filters .filter-subset a.selected, .admin-wrapper .content .muted-hint a, body .muted-hint a, .table a, .notification__message .fa, .drawer--header a:hover, .drawer--header a:focus { + color: rgb(var(--accent-color)) !important; +} + +/* fixes */ + +/* boost hack, v2 */ +/* https://codepen.io/sosuke/pen/Pjoqqp */ +button.icon-button i.fa-retweet { + filter: brightness(0) saturate(100%) invert(31%) sepia(28%) saturate(388%) hue-rotate(115deg) brightness(94%) contrast(90%); /* accent-color-secondary */ + color: transparent !important; +} +button.icon-button.active i.fa-retweet { + filter: brightness(0) saturate(100%) invert(57%) sepia(61%) saturate(481%) hue-rotate(114deg) brightness(93%) contrast(91%); /* accent-color */ +} +button.icon-button.disabled i.fa-retweet, button.icon-button.disabled i.fa-lock { + filter: brightness(0) saturate(100%) invert(31%) sepia(28%) saturate(388%) hue-rotate(115deg) brightness(60%) contrast(90%); /* accent-color-secondary with brightness set to 50% */ +} + +.load-more:hover, .mbstobon-2 .drawer__inner__mastodon, .mbstobon-1 .drawer__inner__mastodon, .mbstobon-0 .drawer__inner__mastodon { + background: inherit; +} + +.account__action-bar__tab, .account__action-bar { + border: none; +} + +.notification__filter-bar, .account__header__bar, .admin-wrapper .content-heading, .admin-wrapper .content h4, .tabs-bar__link:not(.active) { + border-bottom: none; +} + +.dropdown-menu__separator, hr { + opacity: 0; +} +.compose-form .autosuggest-textarea__textarea, .compose-form .spoiler-input__input, .compose-panel .compose-form__autosuggest-wrapper, .mbstobon-3 .drawer__inner__mastodon { + background: transparent; +} +.status, .account, .account__header__fields dl, .account__header__fields, .account__header__bio .account__header__fields, .glitch.local-settings__navigation__item { + border-top: none; + border-bottom: none; +} + +.report-modal__container, .report-modal__comment, .report-modal__comment .setting-text__wrapper { + border-color: rgba(0, 0, 0, 0) !important; +} + +.drawer__inner__mastodon { + background: inherit; +} + +/* misc */ +.column-link:hover, .dropdown-menu__item a:active, .dropdown-menu__item a:focus, .dropdown-menu__item a:hover, header strong.display-name__html { + color: #fff !important; +} + +.notification__filter-bar button.active, .account__section-headline .active { + border-bottom: 3px solid rgb(var(--accent-color)); +} +.notification__filter-bar button:not(.active):hover { + top: -3px; +} +.account__section-headline a.active::after, .account__section-headline a.active::before { + display: none; +} + +.account__header__extra__links a:hover { + text-decoration: underline; +} +.account__section-headline a:hover, .confirmation-modal__cancel-button span { + color: #fff; +} + +.notification__filter-bar button.active::after { + opacity: 0; +} +.notification__filter-bar button.active::before { + opacity: 0; +} + +.column-link__badge, .column-subheading { + background-color: rgb(var(--accent-color)); + animation-name: flash; + animation-duration: 1s; + animation-iteration-count: infinite; + animation-direction: alternate-reverse; +} + +@keyframes flash { + from {background-color: rgb(var(--accent-color));} + to {background-color: rgb(var(--accent-color-secondary));} +} + +.reply-indicator { + max-height: 38px; + overflow-y: hidden; + transition: max-height 1s; +} +.reply-indicator:hover { + max-height: 100%; +} +.reply-indicator:before { + content: 'Replying to:'; + font-size: 12px; + color: rgb(var(--text-color-secondary)); +} + +.getting-started__footer p:after { + content: ' Oat was here'; +} + + +/* public/static css */ +/* for pages like /@username */ + +.public-layout .public-account-header__tabs__tabs .counter.active::after { + border-bottom-color: rgb(var(--accent-color)); +} +.public-layout .public-account-bio .account__header__fields a { + color: rgb(var(--accent-color)); +} +.public-layout .header .nav-button { + color: #fff; + background-color: rgb(var(--accent-color)); +} +.public-layout .header .nav-button:active, .public-layout .header .nav-button:focus, .public-layout .header .nav-button:hover { + background-color: rgb(var(--accent-color-bright)) +} +.public-layout .activity-stream .entry, .hero-widget__text, .table-of-contents { + background-color: rgb(var(--background-color)); +} +body { + background-color: rgb(var(--app-background-color)); +} +.public-layout .public-account-header__tabs__tabs .counter { + border-right: none; +} +.public-layout .public-account-bio, .public-layout .public-account-header__bar::before, .public-layout .header, .directory__tag > a, .directory__tag > div, .directory__tag > a:active, .directory__tag > a:focus, .directory__tag > a:hover, .public-layout .header .brand:hover, .landing-page__call-to-action, .box-widget { + background-color: rgb(var(--background-color-brighter)); +} +.public-layout .display-name, .status__relative-time time, .status__relative-time { + color: rgb(var(--text-color-secondary)); +} +.rich-formatting, .rich-formatting p { + color: rgb(var(--text-color)); +} +.rich-formatting table tbody tr, .rich-formatting table thead tr, .notification-follow, .notification-follow-request { + border-bottom: none; +} + +// https://types.pl/@haskal/106569437674907815 +.search-popout em { + color: rgb(var(--accent-color)) !important; +} + diff --git a/app/javascript/flavours/glitch/styles/statuses.scss b/app/javascript/flavours/glitch/styles/statuses.scss index 947a5d3aed..88fa3ffa07 100644 --- a/app/javascript/flavours/glitch/styles/statuses.scss +++ b/app/javascript/flavours/glitch/styles/statuses.scss @@ -268,7 +268,7 @@ a.button.logo-button { border: 0; background: transparent; padding: 0; - padding-top: 8px; + padding-top: 16px; text-decoration: none; &:hover, diff --git a/app/javascript/flavours/glitch/styles/variables.scss b/app/javascript/flavours/glitch/styles/variables.scss index b865b5a2d1..eaec208468 100644 --- a/app/javascript/flavours/glitch/styles/variables.scss +++ b/app/javascript/flavours/glitch/styles/variables.scss @@ -1,12 +1,12 @@ // Commonly used web colors $black: #000000; // Black $white: #ffffff; // White -$success-green: #79bd9a; // Padua -$error-red: #df405a; // Cerise -$warning-red: #ff5050; // Sunset Orange -$gold-star: #ca8f04; // Dark Goldenrod +$success-green: #79bd9a !default; // Padua +$error-red: #df405a !default; // Cerise +$warning-red: #ff5050 !default; // Sunset Orange +$gold-star: #ca8f04 !default; // Dark Goldenrod -$red-bookmark: $warning-red; +$red-bookmark: $warning-red !default; // Values from the classic Mastodon UI $classic-base-color: #282c37; // Midnight Express diff --git a/app/javascript/flavours/glitch/utils/resize_image.js b/app/javascript/flavours/glitch/utils/resize_image.js index fb8c3c11e6..6c759adbac 100644 --- a/app/javascript/flavours/glitch/utils/resize_image.js +++ b/app/javascript/flavours/glitch/utils/resize_image.js @@ -1,6 +1,6 @@ import EXIF from 'exif-js'; -const MAX_IMAGE_PIXELS = 2073600; // 1920x1080px +const MAX_IMAGE_PIXELS = 16777216; // 4096x4096px const _browser_quirks = {}; diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js index 284c5dbd78..d7d9a8b772 100644 --- a/app/javascript/mastodon/components/status.js +++ b/app/javascript/mastodon/components/status.js @@ -22,6 +22,7 @@ import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_ // We use the component (and not the container) since we do not want // to use the progress bar to show download progress import Bundle from '../features/ui/components/bundle'; +import { visibleReactions } from '../initial_state'; export const textForScreenReader = (intl, status, rebloggedByText = false) => { const displayName = status.getIn(['account', 'display_name']); diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js index efdbf9c908..3415fe2cbf 100644 --- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js +++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js @@ -390,8 +390,8 @@ class EmojiPickerDropdown extends React.PureComponent {

{button || 🙂}
diff --git a/app/javascript/mastodon/features/compose/components/poll_form.js b/app/javascript/mastodon/features/compose/components/poll_form.js index 47ba2fdc35..59d050ebcf 100644 --- a/app/javascript/mastodon/features/compose/components/poll_form.js +++ b/app/javascript/mastodon/features/compose/components/poll_form.js @@ -7,6 +7,7 @@ import IconButton from 'mastodon/components/icon_button'; import Icon from 'mastodon/components/icon'; import AutosuggestInput from 'mastodon/components/autosuggest_input'; import classNames from 'classnames'; +import { pollMinOptions } from 'mastodon/initial_state'; const messages = defineMessages({ option_placeholder: { id: 'compose_form.poll.option_placeholder', defaultMessage: 'Choice {number}' }, @@ -102,7 +103,7 @@ class Option extends React.PureComponent {
- +
); diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js index 4b492a2bb0..0e1bd4e09a 100644 --- a/app/javascript/mastodon/features/status/index.js +++ b/app/javascript/mastodon/features/status/index.js @@ -64,6 +64,7 @@ import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from import { textForScreenReader, defaultMediaVisibility } from '../../components/status'; import Icon from 'mastodon/components/icon'; import { Helmet } from 'react-helmet'; +import { makeCustomEmojiMap } from '../../selectors'; const messages = defineMessages({ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, @@ -225,6 +226,10 @@ class Status extends ImmutablePureComponent { this.props.dispatch(fetchStatus(nextProps.params.statusId)); } + if (nextProps.params.statusId && nextProps.ancestorsIds.size > this.props.ancestorsIds.size) { + this._scrolledIntoView = false; + } + if (nextProps.status && nextProps.status.get('id') !== this.state.loadedStatusId) { this.setState({ showMedia: defaultMediaVisibility(nextProps.status), loadedStatusId: nextProps.status.get('id') }); } diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.js b/app/javascript/mastodon/features/ui/components/navigation_panel.js index 9a9309be05..385dbfdaba 100644 --- a/app/javascript/mastodon/features/ui/components/navigation_panel.js +++ b/app/javascript/mastodon/features/ui/components/navigation_panel.js @@ -60,7 +60,7 @@ class NavigationPanel extends React.Component { )} {showTrends ? ( - + ) : ( )} diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js index b059566061..ca5acf43bd 100644 --- a/app/javascript/mastodon/features/ui/index.js +++ b/app/javascript/mastodon/features/ui/index.js @@ -54,7 +54,7 @@ import { About, PrivacyPolicy, } from './util/async-components'; -import initialState, { me, owner, singleUserMode, showTrends } from '../../initial_state'; +import initialState, { me, owner, singleUserMode, showTrends, timelinePreview } from '../../initial_state'; import { closeOnboarding, INTRODUCTION_VERSION } from 'mastodon/actions/onboarding'; import Header from './components/header'; @@ -163,7 +163,7 @@ class SwitchingColumnsArea extends React.PureComponent { } } else if (singleUserMode && owner && initialState?.accounts[owner]) { redirect = ; - } else if (showTrends) { + } else if (showTrends && (signedIn || timelinePreview)) { redirect = ; } else { redirect = ; diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js index 9db8b2332a..90c2eff56d 100644 --- a/app/javascript/mastodon/initial_state.js +++ b/app/javascript/mastodon/initial_state.js @@ -118,6 +118,7 @@ export const mascot = getMeta('mascot'); export const maxReactions = (initialState && initialState.max_reactions) || 1; export const me = getMeta('me'); export const movedToAccountId = getMeta('moved_to_account_id'); +export const visibleReactions = getMeta('visible_reactions'); export const owner = getMeta('owner'); export const profile_directory = getMeta('profile_directory'); export const reduceMotion = getMeta('reduce_motion'); @@ -140,4 +141,7 @@ export const languages = initialState?.languages; // Glitch-soc-specific settings export const maxChars = (initialState && initialState.max_toot_chars) || 500; +// CatCatNya~ specific settings +export const pollMinOptions = (initialState && initialState.poll_limits && initialState.poll_limits.min_options) || 2; + export default initialState; diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 82e1c7b72c..54138ddb43 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -137,8 +137,8 @@ "compose_form.poll.remove_option": "Auswahlfeld entfernen", "compose_form.poll.switch_to_multiple": "Mehrfachauswahl erlauben", "compose_form.poll.switch_to_single": "Nur Einzelauswahl erlauben", - "compose_form.publish": "Veröffentlichen", - "compose_form.publish_form": "Veröffentlichen", + "compose_form.publish": "Boop", + "compose_form.publish_form": "Boop", "compose_form.publish_loud": "{publish}!", "compose_form.save_changes": "Änderungen speichern", "compose_form.sensitive.hide": "{count, plural, one {Mit einer Inhaltswarnung versehen} other {Mit einer Inhaltswarnung versehen}}", diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json index dcf96600f4..54a1637836 100644 --- a/app/javascript/mastodon/locales/en-GB.json +++ b/app/javascript/mastodon/locales/en-GB.json @@ -17,6 +17,7 @@ "account.badges.group": "Group", "account.block": "Block @{name}", "account.block_domain": "Block domain {domain}", + "account.block_domain": "Block domain {domain}", "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", "account.cancel_follow_request": "Withdraw follow request", @@ -137,8 +138,8 @@ "compose_form.poll.remove_option": "Remove this choice", "compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices", "compose_form.poll.switch_to_single": "Change poll to allow for a single choice", - "compose_form.publish": "Publish", - "compose_form.publish_form": "Publish", + "compose_form.publish": "Boop", + "compose_form.publish_form": "Boop", "compose_form.publish_loud": "{publish}!", "compose_form.save_changes": "Save changes", "compose_form.sensitive.hide": "{count, plural, one {Mark media as sensitive} other {Mark media as sensitive}}", diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index ba9195f118..04bd4796a8 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -141,8 +141,8 @@ "compose_form.poll.remove_option": "Remove this choice", "compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices", "compose_form.poll.switch_to_single": "Change poll to allow for a single choice", - "compose_form.publish": "Publish", - "compose_form.publish_form": "Publish", + "compose_form.publish": "Boop", + "compose_form.publish_form": "Boop", "compose_form.publish_loud": "{publish}!", "compose_form.save_changes": "Save changes", "compose_form.sensitive.hide": "{count, plural, one {Mark media as sensitive} other {Mark media as sensitive}}", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index bc81d9cf26..1eb54138cc 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -387,7 +387,8 @@ "not_signed_in_indicator.not_signed_in": "Vous devez vous connecter pour accéder à cette ressource.", "notification.admin.report": "{name} a signalé {target}", "notification.admin.sign_up": "{name} s'est inscrit·e", - "notification.favourite": "{name} a ajouté le message à ses favoris", + "notification.favourite": "{name} a aimé votre publication", + "notification.reaction": "{name} a réagi·e à votre publication", "notification.follow": "{name} vous suit", "notification.follow_request": "{name} a demandé à vous suivre", "notification.mention": "{name} vous a mentionné·e :", @@ -402,6 +403,7 @@ "notifications.column_settings.admin.sign_up": "Nouvelles inscriptions :", "notifications.column_settings.alert": "Notifications du navigateur", "notifications.column_settings.favourite": "Favoris :", + "notifications.column_settings.reaction": "Réactions:", "notifications.column_settings.filter_bar.advanced": "Afficher toutes les catégories", "notifications.column_settings.filter_bar.category": "Barre de filtrage rapide", "notifications.column_settings.filter_bar.show_bar": "Afficher la barre de filtre", @@ -551,6 +553,7 @@ "status.edited_x_times": "Edité {count, plural, one {{count} fois} other {{count} fois}}", "status.embed": "Intégrer", "status.favourite": "Ajouter aux favoris", + "status.react": "Réagir", "status.filter": "Filtrer ce message", "status.filtered": "Filtré", "status.hide": "Cacher le pouet", @@ -609,6 +612,7 @@ "timeline_hint.resources.statuses": "Les messages plus anciens", "trends.counter_by_accounts": "{count, plural, one {{counter} personne} other {{counter} personnes}} au cours {days, plural, one {des dernières 24h} other {des {days} derniers jours}}", "trends.trending_now": "Tendance en ce moment", + "tooltips.reactions": "Réactions", "ui.beforeunload": "Votre brouillon sera perdu si vous quittez Mastodon.", "units.short.billion": "{count}Md", "units.short.million": "{count}M", diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index 1dafb07fd2..4207d89ff4 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -52,7 +52,7 @@ import { STORE_HYDRATE } from '../actions/store'; import { REDRAFT } from '../actions/statuses'; import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable'; import uuid from '../uuid'; -import { me } from '../initial_state'; +import { me, pollMinOptions } from '../initial_state'; import { unescapeHTML } from '../utils/html'; const initialState = ImmutableMap({ @@ -95,7 +95,7 @@ const initialState = ImmutableMap({ }); const initialPoll = ImmutableMap({ - options: ImmutableList(['', '']), + options: ImmutableList(new Array(pollMinOptions).fill('')), expires_in: 24 * 3600, multiple: false, }); diff --git a/app/javascript/mastodon/utils/resize_image.js b/app/javascript/mastodon/utils/resize_image.js index fb8c3c11e6..6c759adbac 100644 --- a/app/javascript/mastodon/utils/resize_image.js +++ b/app/javascript/mastodon/utils/resize_image.js @@ -1,6 +1,6 @@ import EXIF from 'exif-js'; -const MAX_IMAGE_PIXELS = 2073600; // 1920x1080px +const MAX_IMAGE_PIXELS = 16777216; // 4096x4096px const _browser_quirks = {}; diff --git a/app/javascript/skins/glitch/homogay/common.scss b/app/javascript/skins/glitch/homogay/common.scss new file mode 100644 index 0000000000..4dfd68d267 --- /dev/null +++ b/app/javascript/skins/glitch/homogay/common.scss @@ -0,0 +1 @@ +@import 'flavours/glitch/styles/homogay'; diff --git a/app/javascript/skins/glitch/homogay/names.yml b/app/javascript/skins/glitch/homogay/names.yml new file mode 100644 index 0000000000..968051de57 --- /dev/null +++ b/app/javascript/skins/glitch/homogay/names.yml @@ -0,0 +1,16 @@ +de: + skins: + glitch: + homogay: homogay (von @anna@girldick.gay) +en: + skins: + glitch: + homogay: homogay (by @anna@girldick.gay) +es: + skins: + glitch: + homogay: homogay (por @anna@girldick.gay) +fr: + skins: + glitch: + homogay: homogay (par @anna@girldick.gay) diff --git a/app/javascript/skins/glitch/oatstodon/common.scss b/app/javascript/skins/glitch/oatstodon/common.scss new file mode 100644 index 0000000000..4c6f4af978 --- /dev/null +++ b/app/javascript/skins/glitch/oatstodon/common.scss @@ -0,0 +1 @@ +@import 'flavours/glitch/styles/oatstodon'; diff --git a/app/javascript/skins/glitch/oatstodon/names.yml b/app/javascript/skins/glitch/oatstodon/names.yml new file mode 100644 index 0000000000..dfc72b37f6 --- /dev/null +++ b/app/javascript/skins/glitch/oatstodon/names.yml @@ -0,0 +1,8 @@ +en: + skins: + glitch: + oatstodon: oatstodon (by @oat@hellsite.site) +es: + skins: + glitch: + oatstodon: oatstodon (por @oat@hellsite.site) diff --git a/app/lib/rate_limiter.rb b/app/lib/rate_limiter.rb index 0e2c9a8943..e9b7722f8a 100644 --- a/app/lib/rate_limiter.rb +++ b/app/lib/rate_limiter.rb @@ -6,12 +6,12 @@ class RateLimiter FAMILIES = { follows: { limit: 400, - period: 24.hours.freeze, + period: 12.hours.freeze, }.freeze, statuses: { limit: 300, - period: 3.hours.freeze, + period: 1.hour.freeze, }.freeze, reports: { diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index f2b34e4cd1..64c679cb89 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -68,7 +68,7 @@ class MediaAttachment < ApplicationRecord IMAGE_STYLES = { original: { - pixels: 2_073_600, # 1920x1080px + pixels: 16_777_216, # 4096x4096px file_geometry_parser: FastGeometryParser, }.freeze, diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb index f337ed35b2..fd91872250 100644 --- a/app/serializers/initial_state_serializer.rb +++ b/app/serializers/initial_state_serializer.rb @@ -21,6 +21,7 @@ class InitialStateSerializer < ActiveModel::Serializer def poll_limits { + min_options: PollValidator::MIN_OPTIONS, max_options: PollValidator::MAX_OPTIONS, max_option_chars: PollValidator::MAX_OPTION_CHARS, min_expiration: PollValidator::MIN_EXPIRATION, diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb index 5ae1099d04..23525116d6 100644 --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@ -67,6 +67,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer }, polls: { + min_options: PollValidator::MIN_OPTIONS, max_options: PollValidator::MAX_OPTIONS, max_characters_per_option: PollValidator::MAX_OPTION_CHARS, min_expiration: PollValidator::MIN_EXPIRATION, diff --git a/app/serializers/rest/v1/instance_serializer.rb b/app/serializers/rest/v1/instance_serializer.rb index 389ec7dffc..0262f10d01 100644 --- a/app/serializers/rest/v1/instance_serializer.rb +++ b/app/serializers/rest/v1/instance_serializer.rb @@ -42,6 +42,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer def poll_limits { + min_options: PollValidator::MIN_OPTIONS, max_options: PollValidator::MAX_OPTIONS, max_option_chars: PollValidator::MAX_OPTION_CHARS, min_expiration: PollValidator::MIN_EXPIRATION, @@ -91,6 +92,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer }, polls: { + min_options: PollValidator::MIN_OPTIONS, max_options: PollValidator::MAX_OPTIONS, max_characters_per_option: PollValidator::MAX_OPTION_CHARS, min_expiration: PollValidator::MIN_EXPIRATION, diff --git a/app/validators/poll_validator.rb b/app/validators/poll_validator.rb index 1aaf5a5d02..da7bf3daff 100644 --- a/app/validators/poll_validator.rb +++ b/app/validators/poll_validator.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true class PollValidator < ActiveModel::Validator - MAX_OPTIONS = (ENV['MAX_POLL_OPTIONS'] || 5).to_i + MIN_OPTIONS = [1, (ENV['MIN_POLL_OPTIONS'] || 2).to_i].max + MAX_OPTIONS = [MIN_OPTIONS, (ENV['MAX_POLL_OPTIONS'] || 5).to_i].max MAX_OPTION_CHARS = (ENV['MAX_POLL_OPTION_CHARS'] || 100).to_i MAX_EXPIRATION = 1.month.freeze MIN_EXPIRATION = 5.minutes.freeze @@ -9,7 +10,7 @@ class PollValidator < ActiveModel::Validator def validate(poll) current_time = Time.now.utc - poll.errors.add(:options, I18n.t('polls.errors.too_few_options')) unless poll.options.size > 1 + poll.errors.add(:options, I18n.t('polls.errors.too_few_options')) unless poll.options.size >= MIN_OPTIONS poll.errors.add(:options, I18n.t('polls.errors.too_many_options', max: MAX_OPTIONS)) if poll.options.size > MAX_OPTIONS poll.errors.add(:options, I18n.t('polls.errors.over_character_limit', max: MAX_OPTION_CHARS)) if poll.options.any? { |option| option.mb_chars.grapheme_length > MAX_OPTION_CHARS } poll.errors.add(:options, I18n.t('polls.errors.duplicate_options')) unless poll.options.uniq.size == poll.options.size diff --git a/app/views/accounts/show.rss.ruby b/app/views/accounts/show.rss.ruby index 34e29d483f..30cb42f8d0 100644 --- a/app/views/accounts/show.rss.ruby +++ b/app/views/accounts/show.rss.ruby @@ -9,6 +9,7 @@ RSS::Builder.build do |doc| @statuses.each do |status| doc.item do |item| + item.title("New post#{" (CW: #{status.spoiler_text})" unless status.spoiler_text.empty?}") item.link(ActivityPub::TagManager.instance.url_for(status)) item.pub_date(status.created_at) item.description(rss_status_content_format(status)) diff --git a/app/views/tags/show.rss.ruby b/app/views/tags/show.rss.ruby index 8e0c2327b5..25f76610ff 100644 --- a/app/views/tags/show.rss.ruby +++ b/app/views/tags/show.rss.ruby @@ -7,6 +7,7 @@ RSS::Builder.build do |doc| @statuses.each do |status| doc.item do |item| + item.title("New post by #{status.account.pretty_acct}#{" (CW: #{status.spoiler_text})" unless status.spoiler_text.empty?}") item.link(ActivityPub::TagManager.instance.url_for(status)) item.pub_date(status.created_at) item.description(rss_status_content_format(status)) diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index 72ef7ba801..13ffd76987 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -62,7 +62,7 @@ class Rack::Attack IpBlock.blocked?(req.remote_ip) end - throttle('throttle_authenticated_api', limit: 300, period: 5.minutes) do |req| + throttle('throttle_authenticated_api', limit: 600, period: 5.minutes) do |req| req.authenticated_user_id if req.api_request? end @@ -70,11 +70,11 @@ class Rack::Attack req.throttleable_remote_ip if req.api_request? && req.unauthenticated? end - throttle('throttle_api_media', limit: 30, period: 30.minutes) do |req| + throttle('throttle_api_media', limit: 100, period: 30.minutes) do |req| req.authenticated_user_id if req.post? && req.path.match?(/\A\/api\/v\d+\/media\z/i) end - throttle('throttle_media_proxy', limit: 30, period: 10.minutes) do |req| + throttle('throttle_media_proxy', limit: 200, period: 10.minutes) do |req| req.throttleable_remote_ip if req.path.start_with?('/media_proxy') end @@ -82,7 +82,7 @@ class Rack::Attack req.throttleable_remote_ip if req.post? && req.path == '/api/v1/accounts' end - throttle('throttle_authenticated_paging', limit: 300, period: 15.minutes) do |req| + throttle('throttle_authenticated_paging', limit: 1000, period: 15.minutes) do |req| req.authenticated_user_id if req.paging_request? end @@ -93,7 +93,7 @@ class Rack::Attack API_DELETE_REBLOG_REGEX = /\A\/api\/v1\/statuses\/[\d]+\/unreblog\z/.freeze API_DELETE_STATUS_REGEX = /\A\/api\/v1\/statuses\/[\d]+\z/.freeze - throttle('throttle_api_delete', limit: 30, period: 30.minutes) do |req| + throttle('throttle_api_delete', limit: 60, period: 5.minutes) do |req| req.authenticated_user_id if (req.post? && req.path.match?(API_DELETE_REBLOG_REGEX)) || (req.delete? && req.path.match?(API_DELETE_STATUS_REGEX)) end diff --git a/config/settings.yml b/config/settings.yml index 28951cea10..1ecc870a68 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -2,7 +2,7 @@ # important settings can be changed from the admin interface. defaults: &defaults - site_title: 'Mastodon Glitch Edition' + site_title: 'nyastodon' site_short_description: '' site_description: '' site_extended_description: '' diff --git a/config/sidekiq.yml b/config/sidekiq.yml index 05c5b28c86..8de744bf9e 100644 --- a/config/sidekiq.yml +++ b/config/sidekiq.yml @@ -39,7 +39,7 @@ class: Scheduler::UserCleanupScheduler queue: scheduler ip_cleanup_scheduler: - cron: '<%= Random.rand(0..59) %> <%= Random.rand(3..5) %> * * *' + every: '1h' class: Scheduler::IpCleanupScheduler queue: scheduler pghero_scheduler: diff --git a/dist/mastodon-sidekiq.service b/dist/mastodon-sidekiq.service index 324cd5a398..3f4c806048 100644 --- a/dist/mastodon-sidekiq.service +++ b/dist/mastodon-sidekiq.service @@ -47,6 +47,11 @@ SystemCallFilter=~@cpu-emulation @debug @keyring @ipc @mount @obsolete @privileg SystemCallFilter=@chown SystemCallFilter=pipe SystemCallFilter=pipe2 +Nice=19 +CPUSchedulingPolicy=idle +CPUSchedulingPriority=1 +IOSchedulingClass=idle +IOSchedulingPriority=7 ReadWritePaths=/home/mastodon/live [Install] diff --git a/dist/mastodon-streaming.service b/dist/mastodon-streaming.service index cf1f2d8bc6..fdd280d8e1 100644 --- a/dist/mastodon-streaming.service +++ b/dist/mastodon-streaming.service @@ -9,6 +9,7 @@ WorkingDirectory=/home/mastodon/live Environment="NODE_ENV=production" Environment="PORT=4000" Environment="STREAMING_CLUSTER_NUM=1" +Environment="LD_PRELOAD=libjemalloc.so" ExecStart=/usr/bin/node ./streaming TimeoutSec=15 Restart=always diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index 6b423f6fcf..1d63b22329 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -21,7 +21,19 @@ module Mastodon end def suffix - '+glitch' + '+cat' + end + + def suffix_version + '+1.0.7' + end + + def post_suffix + '+nya' + end + + def post_suffix_version + '-1.1.5' end def to_a @@ -29,11 +41,11 @@ module Mastodon end def to_s - [to_a.join('.'), flags, suffix].join + [to_a.join('.'), flags, suffix, suffix_version, post_suffix, post_suffix_version].join end def repository - ENV.fetch('GITHUB_REPOSITORY', 'glitch-soc/mastodon') + ENV.fetch('GITHUB_REPOSITORY', 'CatCatNya/catstodon') end def source_base_url diff --git a/public/avatars/original/missing.png b/public/avatars/original/missing.png index 781370782e..ebcbc561ee 100644 Binary files a/public/avatars/original/missing.png and b/public/avatars/original/missing.png differ diff --git a/public/blobCat.png b/public/blobCat.png new file mode 100644 index 0000000000..08e1b40807 Binary files /dev/null and b/public/blobCat.png differ diff --git a/public/sounds/boop.mp3 b/public/sounds/boop.mp3 index bf9c3c1aaf..2489e19db6 100644 Binary files a/public/sounds/boop.mp3 and b/public/sounds/boop.mp3 differ diff --git a/public/sounds/boop.ogg b/public/sounds/boop.ogg index a6551c9fdd..78df190256 100644 Binary files a/public/sounds/boop.ogg and b/public/sounds/boop.ogg differ diff --git a/redact-env.bash b/redact-env.bash new file mode 100755 index 0000000000..0249f3fb06 --- /dev/null +++ b/redact-env.bash @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +if [[ -f "$1" ]]; then + sed -e '/^#.*$/d' \ + -e 's/^SECRET_KEY_BASE=.*/SECRET_KEY_BASE=[REDACTED]/gi' \ + -e 's/^OTP_SECRET=.*/OTP_SECRET=[REDACTED]/gi' \ + -e 's/^VAPID_PRIVATE_KEY=.*/VAPID_PRIVATE_KEY=[REDACTED]/gi' \ + -e 's/^VAPID_PUBLIC_KEY=.*/VAPID_PUBLIC_KEY=[REDACTED]/gi' \ + -e 's/^DB_HOST=.*/DB_HOST=[REDACTED]/gi' \ + -e 's/^DB_PORT=.*/DB_PORT=[REDACTED]/gi' \ + -e 's/^DB_NAME=.*/DB_NAME=[REDACTED]/gi' \ + -e 's/^DB_USER=.*/DB_USER=[REDACTED]/gi' \ + -e 's/^DB_PASS=.*/DB_PASS=[REDACTED]/gi' \ + -e 's/^REDIS_HOST=.*/REDIS_HOST=[REDACTED]/gi' \ + -e 's/^REDIS_PORT=.*/REDIS_PORT=[REDACTED]/gi' \ + -e 's/^REDIS_PASSWORD=.*/REDIS_PASSWORD=[REDACTED]/gi' \ + -e 's/^PAPERCLIP_ROOT_PATH=.*/PAPERCLIP_ROOT_PATH=[REDACTED]/gi' \ + -e 's/^SMTP_PORT=.*/SMTP_PORT=[REDACTED]/gi' \ + -e 's/^SMTP_LOGIN=.*/SMTP_LOGIN=[REDACTED]/gi' \ + -e 's/^SMTP_PASSWORD=.*/SMTP_PASSWORD=[REDACTED]/gi' \ + -e 's/^SMTP_AUTH_METHOD=.*/SMTP_AUTH_METHOD=[REDACTED]/gi' \ + -e 's/^SMTP_OPENSSL_VERIFY_MODE=.*/SMTP_OPENSSL_VERIFY_MODE=[REDACTED]/gi' \ + -e 's/^ES_HOST=.*/ES_HOST=[REDACTED]/gi' \ + -e 's/^ES_PORT=.*/ES_PORT=[REDACTED]/gi' \ + -e 's/^ES_PREFIX=.*/ES_PREFIX=[REDACTED]/gi' \ + "$1" +fi