forked from mirrors/catstodon
merge nyastodon-specific changes back in
This was caused by an accidental rebase that i "fixed" by force-pushing, which caused nyastodon to be even with glitch-soc/main. oops.
This commit is contained in:
commit
57b7968504
83 changed files with 1153 additions and 230 deletions
|
@ -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:
|
||||
|
|
44
.env.production.catcatnya
Normal file
44
.env.production.catcatnya
Normal file
|
@ -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 <no-reply@catcatnya.com>'
|
||||
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
|
|
@ -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
|
||||
|
||||
|
|
44
.github/workflows/build-image.yml
vendored
44
.github/workflows/build-image.yml
vendored
|
@ -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
|
|
@ -1 +1 @@
|
|||
3.0.4
|
||||
3.0.5
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 ##
|
||||
|
||||
|
|
165
Gemfile.lock
165
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
|
||||
|
|
39
README.md
39
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
|
||||
<br>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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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 <div className='media-gallery' style={{ height: '110px' }} />;
|
||||
}
|
||||
|
@ -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')}
|
||||
|
|
|
@ -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 (
|
||||
<div className='translate-button'>
|
||||
<div className='translate-button__meta'>
|
||||
<FormattedMessage id='status.translated_from_with' defaultMessage='Translated from {lang} using {provider}' values={{ lang: languageName, provider }} />
|
||||
</div>
|
||||
|
||||
<button className='link-button' onClick={onClick}>
|
||||
<FormattedMessage id='status.show_original' defaultMessage='Show original' />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<button className='status__content__read-more-button' onClick={onClick}>
|
||||
<FormattedMessage id='status.translate' defaultMessage='Translate' />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 && (
|
||||
<TranslateButton onClick={this.handleTranslate} translation={status.get('translation')} />
|
||||
);
|
||||
|
||||
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}
|
||||
</div>
|
||||
|
||||
{extraMedia}
|
||||
|
||||
</div>
|
||||
);
|
||||
} else if (parseClick) {
|
||||
|
@ -375,6 +429,7 @@ export default class StatusContent extends React.PureComponent {
|
|||
onMouseLeave={this.handleMouseLeave}
|
||||
lang={lang}
|
||||
/>
|
||||
{translateButton}
|
||||
{media}
|
||||
{extraMedia}
|
||||
</div>
|
||||
|
@ -395,6 +450,7 @@ export default class StatusContent extends React.PureComponent {
|
|||
onMouseLeave={this.handleMouseLeave}
|
||||
lang={lang}
|
||||
/>
|
||||
{translateButton}
|
||||
{media}
|
||||
{extraMedia}
|
||||
</div>
|
||||
|
|
|
@ -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));
|
||||
},
|
||||
|
|
|
@ -392,8 +392,8 @@ class EmojiPickerDropdown extends React.PureComponent {
|
|||
<div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>
|
||||
{button || <img
|
||||
className={classNames('emojione', { 'pulse-loading': active && loading })}
|
||||
alt='🙂'
|
||||
src={`${assetHost}/emoji/1f602.svg`}
|
||||
alt='blobCat emoji'
|
||||
src={`${assetHost}/blobCat.png`}
|
||||
/>}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ class Option extends React.PureComponent {
|
|||
</label>
|
||||
|
||||
<div className='poll__cancel'>
|
||||
<IconButton disabled={index <= 1} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />
|
||||
<IconButton disabled={index < pollLimits.min_options} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
|
|
|
@ -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' },
|
||||
|
|
|
@ -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' },
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
|||
</fieldset>
|
||||
</div>
|
||||
);
|
||||
} else if (placeholder) {
|
||||
} else if (placeholder || number) {
|
||||
return (
|
||||
<div className='glitch local-settings__page__item string'>
|
||||
<label htmlFor={id}>
|
||||
|
@ -84,7 +85,7 @@ export default class LocalSettingsPageItem extends React.PureComponent {
|
|||
<p>
|
||||
<input
|
||||
id={id}
|
||||
type='text'
|
||||
type={number ? 'number' : 'text'}
|
||||
value={settings.getIn(item)}
|
||||
placeholder={placeholder}
|
||||
onChange={handleChange}
|
||||
|
|
|
@ -35,6 +35,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
onOpenMedia: PropTypes.func.isRequired,
|
||||
onOpenVideo: PropTypes.func.isRequired,
|
||||
onToggleHidden: PropTypes.func,
|
||||
onTranslate: PropTypes.func.isRequired,
|
||||
expanded: PropTypes.bool,
|
||||
measureHeight: PropTypes.bool,
|
||||
onHeightChange: PropTypes.func,
|
||||
|
@ -116,6 +117,11 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
window.open(href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
|
||||
}
|
||||
|
||||
handleTranslate = () => {
|
||||
const { onTranslate, status } = this.props;
|
||||
onTranslate(status);
|
||||
}
|
||||
|
||||
render () {
|
||||
const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status;
|
||||
const { expanded, onToggleHidden, settings, usingPiP, intl } = this.props;
|
||||
|
@ -309,6 +315,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
expanded={expanded}
|
||||
collapsed={false}
|
||||
onExpandedToggle={onToggleHidden}
|
||||
onTranslate={this.handleTranslate}
|
||||
parseClick={this.parseClick}
|
||||
onUpdate={this.handleChildUpdate}
|
||||
tagLinks={settings.get('tag_misleading_links')}
|
||||
|
|
|
@ -35,7 +35,9 @@ import {
|
|||
deleteStatus,
|
||||
editStatus,
|
||||
hideStatus,
|
||||
revealStatus
|
||||
revealStatus,
|
||||
translateStatus,
|
||||
undoStatusTranslation,
|
||||
} from 'flavours/glitch/actions/statuses';
|
||||
import { initMuteModal } from 'flavours/glitch/actions/mutes';
|
||||
import { initBlockModal } from 'flavours/glitch/actions/blocks';
|
||||
|
@ -56,6 +58,7 @@ import { autoUnfoldCW } from 'flavours/glitch/utils/content_warning';
|
|||
import { textForScreenReader, defaultMediaVisibility } from 'flavours/glitch/components/status';
|
||||
import Icon from 'flavours/glitch/components/icon';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { makeCustomEmojiMap } from '../../selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
|
||||
|
@ -459,6 +462,16 @@ class Status extends ImmutablePureComponent {
|
|||
this.setState({ isExpanded: !isExpanded, threadExpanded: !isExpanded });
|
||||
}
|
||||
|
||||
handleTranslate = status => {
|
||||
const { dispatch } = this.props;
|
||||
|
||||
if (status.get('translation')) {
|
||||
dispatch(undoStatusTranslation(status.get('id')));
|
||||
} else {
|
||||
dispatch(translateStatus(status.get('id')));
|
||||
}
|
||||
}
|
||||
|
||||
handleBlockClick = (status) => {
|
||||
const { dispatch } = this.props;
|
||||
const account = status.get('account');
|
||||
|
@ -690,6 +703,7 @@ class Status extends ImmutablePureComponent {
|
|||
onReactionRemove={this.handleReactionRemove}
|
||||
expanded={isExpanded}
|
||||
onToggleHidden={this.handleToggleHidden}
|
||||
onTranslate={this.handleTranslate}
|
||||
domain={domain}
|
||||
showMedia={this.state.showMedia}
|
||||
onToggleMediaVisibility={this.handleToggleMediaVisibility}
|
||||
|
|
|
@ -75,11 +75,9 @@ class LinkFooter extends React.PureComponent {
|
|||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Mastodon</strong>:
|
||||
<strong>nyastodon</strong>:
|
||||
{' '}
|
||||
<a href='https://joinmastodon.org' target='_blank'><FormattedMessage id='footer.about' defaultMessage='About' /></a>
|
||||
{' · '}
|
||||
<a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='footer.get_app' defaultMessage='Get the app' /></a>
|
||||
<a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='footer.about' defaultMessage='About' /></a>
|
||||
{' · '}
|
||||
<Link to='/keyboard-shortcuts'><FormattedMessage id='footer.keyboard_shortcuts' defaultMessage='Keyboard shortcuts' /></Link>
|
||||
{' · '}
|
||||
|
@ -87,6 +85,8 @@ class LinkFooter extends React.PureComponent {
|
|||
{' · '}
|
||||
v{version}
|
||||
</p>
|
||||
|
||||
<p>be gay do crime uwu</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ class NavigationPanel extends React.Component {
|
|||
)}
|
||||
|
||||
{showTrends ? (
|
||||
<ColumnLink transparent to='/explore' icon='hashtag' text={intl.formatMessage(messages.explore)} />
|
||||
<ColumnLink transparent to={(signedIn || timelinePreview) ? '/explore' : '/explore/tags'} icon='hashtag' text={intl.formatMessage(messages.explore)} />
|
||||
) : (
|
||||
<ColumnLink transparent to='/search' icon='search' text={intl.formatMessage(messages.search)} />
|
||||
)}
|
||||
|
|
|
@ -144,10 +144,11 @@ const PageSix = ({ admin, domain }) => {
|
|||
<p>
|
||||
<FormattedMessage
|
||||
id='onboarding.page_six.github'
|
||||
defaultMessage='{domain} runs on Glitchsoc. Glitchsoc is a friendly {fork} of {Mastodon}. Glitchsoc is fully compatible with all Mastodon apps and instances. Glitchsoc is free open-source software. You can report bugs, request features, or contribute to the code on {github}.'
|
||||
defaultMessage='{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}.'
|
||||
values={{
|
||||
domain,
|
||||
fork: <a href='https://en.wikipedia.org/wiki/Fork_(software_development)' target='_blank' rel='noopener'>fork</a>,
|
||||
glitchsoc: <a href='https://github.com/glitch-soc/mastodon' target='_blank' rel='noopener'>Glitchsoc</a>,
|
||||
Mastodon: <a href='https://github.com/mastodon/mastodon' target='_blank' rel='noopener'>Mastodon</a>,
|
||||
github: <a href={source_url} target='_blank' rel='noopener'>GitHub</a>,
|
||||
}}
|
||||
|
|
|
@ -65,6 +65,7 @@ import Header from './components/header';
|
|||
// Dummy import, to make sure that <Status /> 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 = <Redirect from='/' to={`/@${initialState.accounts[owner].username}`} exact />;
|
||||
} else if (showTrends) {
|
||||
} else if (showTrends && (signedIn || timelinePreview)) {
|
||||
redirect = <Redirect from='/' to='/explore' exact />;
|
||||
} else {
|
||||
redirect = <Redirect from='/' to='/about' exact />;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:',
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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': 'すべて',
|
||||
|
|
|
@ -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': '모바일 앱',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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);
|
||||
export default Object.assign({}, inherited, messages);
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
4
app/javascript/flavours/glitch/styles/homogay.scss
Normal file
4
app/javascript/flavours/glitch/styles/homogay.scss
Normal file
|
@ -0,0 +1,4 @@
|
|||
@import 'homogay/variables';
|
||||
@import 'index';
|
||||
@import 'homogay/diff';
|
||||
|
109
app/javascript/flavours/glitch/styles/homogay/animations.scss
Normal file
109
app/javascript/flavours/glitch/styles/homogay/animations.scss
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
161
app/javascript/flavours/glitch/styles/homogay/diff.scss
Normal file
161
app/javascript/flavours/glitch/styles/homogay/diff.scss
Normal file
|
@ -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';
|
53
app/javascript/flavours/glitch/styles/homogay/variables.scss
Normal file
53
app/javascript/flavours/glitch/styles/homogay/variables.scss
Normal file
|
@ -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;
|
332
app/javascript/flavours/glitch/styles/oatstodon.scss
Normal file
332
app/javascript/flavours/glitch/styles/oatstodon.scss
Normal file
|
@ -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;
|
||||
}
|
||||
|
|
@ -268,7 +268,7 @@ a.button.logo-button {
|
|||
border: 0;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
padding-top: 8px;
|
||||
padding-top: 16px;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import EXIF from 'exif-js';
|
||||
|
||||
const MAX_IMAGE_PIXELS = 2073600; // 1920x1080px
|
||||
const MAX_IMAGE_PIXELS = 16777216; // 4096x4096px
|
||||
|
||||
const _browser_quirks = {};
|
||||
|
||||
|
|
|
@ -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']);
|
||||
|
|
|
@ -390,8 +390,8 @@ class EmojiPickerDropdown extends React.PureComponent {
|
|||
<div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>
|
||||
{button || <img
|
||||
className={classNames('emojione', { 'pulse-loading': active && loading })}
|
||||
alt='🙂'
|
||||
src={`${assetHost}/emoji/1f602.svg`}
|
||||
alt='blobCat emoji'
|
||||
src={`${assetHost}/blobCat.png`}
|
||||
/>}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -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 {
|
|||
</label>
|
||||
|
||||
<div className='poll__cancel'>
|
||||
<IconButton disabled={index <= 1} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />
|
||||
<IconButton disabled={index < pollMinOptions} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
|
|
|
@ -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') });
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ class NavigationPanel extends React.Component {
|
|||
)}
|
||||
|
||||
{showTrends ? (
|
||||
<ColumnLink transparent to='/explore' icon='hashtag' text={intl.formatMessage(messages.explore)} />
|
||||
<ColumnLink transparent to={(signedIn || timelinePreview) ? '/explore' : '/explore/tags'} icon='hashtag' text={intl.formatMessage(messages.explore)} />
|
||||
) : (
|
||||
<ColumnLink transparent to='/search' icon='search' text={intl.formatMessage(messages.search)} />
|
||||
)}
|
||||
|
|
|
@ -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 = <Redirect from='/' to={`/@${initialState.accounts[owner].username}`} exact />;
|
||||
} else if (showTrends) {
|
||||
} else if (showTrends && (signedIn || timelinePreview)) {
|
||||
redirect = <Redirect from='/' to='/explore' exact />;
|
||||
} else {
|
||||
redirect = <Redirect from='/' to='/about' exact />;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}}",
|
||||
|
|
|
@ -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}}",
|
||||
|
|
|
@ -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}}",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import EXIF from 'exif-js';
|
||||
|
||||
const MAX_IMAGE_PIXELS = 2073600; // 1920x1080px
|
||||
const MAX_IMAGE_PIXELS = 16777216; // 4096x4096px
|
||||
|
||||
const _browser_quirks = {};
|
||||
|
||||
|
|
1
app/javascript/skins/glitch/homogay/common.scss
Normal file
1
app/javascript/skins/glitch/homogay/common.scss
Normal file
|
@ -0,0 +1 @@
|
|||
@import 'flavours/glitch/styles/homogay';
|
16
app/javascript/skins/glitch/homogay/names.yml
Normal file
16
app/javascript/skins/glitch/homogay/names.yml
Normal file
|
@ -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)
|
1
app/javascript/skins/glitch/oatstodon/common.scss
Normal file
1
app/javascript/skins/glitch/oatstodon/common.scss
Normal file
|
@ -0,0 +1 @@
|
|||
@import 'flavours/glitch/styles/oatstodon';
|
8
app/javascript/skins/glitch/oatstodon/names.yml
Normal file
8
app/javascript/skins/glitch/oatstodon/names.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
en:
|
||||
skins:
|
||||
glitch:
|
||||
oatstodon: oatstodon (by @oat@hellsite.site)
|
||||
es:
|
||||
skins:
|
||||
glitch:
|
||||
oatstodon: oatstodon (por @oat@hellsite.site)
|
|
@ -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: {
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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: ''
|
||||
|
|
|
@ -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:
|
||||
|
|
5
dist/mastodon-sidekiq.service
vendored
5
dist/mastodon-sidekiq.service
vendored
|
@ -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]
|
||||
|
|
1
dist/mastodon-streaming.service
vendored
1
dist/mastodon-streaming.service
vendored
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 8.7 KiB |
BIN
public/blobCat.png
Normal file
BIN
public/blobCat.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.1 KiB |
Binary file not shown.
Binary file not shown.
27
redact-env.bash
Executable file
27
redact-env.bash
Executable file
|
@ -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
|
Loading…
Reference in a new issue