Compare commits
53 commits
0d1e55d566
...
52aeef3834
Author | SHA1 | Date | |
---|---|---|---|
52aeef3834 | |||
8aae9712d9 | |||
|
bb4c06aa95 | ||
|
a1c7ba38b7 | ||
|
c2887ef289 | ||
|
486e4bc7d3 | ||
|
40439399c6 | ||
|
53b73ed6a2 | ||
|
436419cc2f | ||
|
3c3ef8b9d3 | ||
|
eae436c5a8 | ||
|
b83076647e | ||
|
7100106f3f | ||
|
04da8f887b | ||
|
d9d0a6ef33 | ||
|
93b365bfc0 | ||
|
e3c4e90646 | ||
|
084d051e6c | ||
|
34f677cd03 | ||
|
7719de5665 | ||
|
c249c10f74 | ||
|
c379487041 | ||
|
342709ecb2 | ||
|
eea2364a76 | ||
|
191445ed32 | ||
|
d391e01b59 | ||
|
3f89cec3c9 | ||
|
f6f62002c7 | ||
|
189b70cd6a | ||
|
8c76a208ed | ||
|
65eb943b9d | ||
|
19f1ffe287 | ||
|
5ea36a3606 | ||
|
b27cad27c2 | ||
|
63f1f1465a | ||
|
4cd00c0dd9 | ||
|
c6f7e3a1fb | ||
|
93aa783aa1 | ||
|
868333c86f | ||
|
ac49514bd6 | ||
|
a2611d782c | ||
|
541cbdd963 | ||
|
08e511cecb | ||
|
f50b12fe6e | ||
|
8fd45df06e | ||
|
98ae4ef813 | ||
|
94a0b7a7f0 | ||
|
46d70b1ca6 | ||
|
aa8741fff3 | ||
|
cca4f085d6 | ||
|
43e58d1558 | ||
|
5bc39b3196 | ||
|
c3936cbbe3 |
|
@ -252,6 +252,11 @@ SMTP_FROM_ADDRESS=notifications@example.com
|
||||||
# Maximum allowed character count
|
# Maximum allowed character count
|
||||||
MAX_TOOT_CHARS=500
|
MAX_TOOT_CHARS=500
|
||||||
|
|
||||||
|
# Maximum allowed hashtags to follow in a feed column
|
||||||
|
# Note that setting this value higher may cause significant
|
||||||
|
# database load
|
||||||
|
MAX_FEED_HASHTAGS=4
|
||||||
|
|
||||||
# Maximum number of pinned posts
|
# Maximum number of pinned posts
|
||||||
MAX_PINNED_TOOTS=5
|
MAX_PINNED_TOOTS=5
|
||||||
|
|
||||||
|
@ -270,9 +275,6 @@ MAX_POLL_OPTIONS=5
|
||||||
# Maximum allowed poll option characters
|
# Maximum allowed poll option characters
|
||||||
MAX_POLL_OPTION_CHARS=100
|
MAX_POLL_OPTION_CHARS=100
|
||||||
|
|
||||||
# Maximum number of emoji reactions per toot and user (minimum 1)
|
|
||||||
MAX_REACTIONS=1
|
|
||||||
|
|
||||||
# Maximum image and video/audio upload sizes
|
# Maximum image and video/audio upload sizes
|
||||||
# Units are in bytes
|
# Units are in bytes
|
||||||
# 1048576 bytes equals 1 megabyte
|
# 1048576 bytes equals 1 megabyte
|
||||||
|
|
4
.github/workflows/build-security.yml
vendored
|
@ -36,7 +36,7 @@ jobs:
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=edge
|
type=raw,value=edge
|
||||||
type=raw,value=nightly
|
type=raw,value=nightly
|
||||||
type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }}
|
type=raw,value=${{ needs.compute-suffix.outputs.prerelease }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
build-image-streaming:
|
build-image-streaming:
|
||||||
|
@ -57,5 +57,5 @@ jobs:
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=edge
|
type=raw,value=edge
|
||||||
type=raw,value=nightly
|
type=raw,value=nightly
|
||||||
type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }}
|
type=raw,value=${{ needs.compute-suffix.outputs.prerelease }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
variables:
|
variables:
|
||||||
environment: &docker-environment
|
environment: &docker-environment
|
||||||
NAME: gitea.treehouse.systems/treehouse/mastodon
|
SERVER_IMAGE: gitea.treehouse.systems/treehouse/mastodon
|
||||||
|
STREAMING_IMAGE: gitea.treehouse.systems/treehouse/mastodon-streaming
|
||||||
DATE_COMMAND: export COMMIT_DATE=$(date -u -Idate -d @$(git show -s --format=%ct))
|
DATE_COMMAND: export COMMIT_DATE=$(date -u -Idate -d @$(git show -s --format=%ct))
|
||||||
docker-step: &docker-step
|
docker-step: &docker-step
|
||||||
image: docker:rc-git
|
image: docker:rc-git
|
||||||
|
@ -17,43 +18,18 @@ clone:
|
||||||
depth: 10
|
depth: 10
|
||||||
|
|
||||||
pipeline:
|
pipeline:
|
||||||
# build-base:
|
|
||||||
# <<: *docker-step
|
|
||||||
# commands:
|
|
||||||
# - docker version
|
|
||||||
# - docker image build -f Dockerfile --build-arg SOURCE_TAG=$CI_COMMIT_SHA . --target build-base -t $NAME:build-base
|
|
||||||
|
|
||||||
# build:
|
|
||||||
# <<: *docker-step
|
|
||||||
# commands:
|
|
||||||
# - docker version
|
|
||||||
# - docker image build -f Dockerfile --build-arg SOURCE_TAG=$CI_COMMIT_SHA . --target build -t $NAME:build
|
|
||||||
|
|
||||||
# output-base:
|
|
||||||
# <<: *docker-step
|
|
||||||
# commands:
|
|
||||||
# - docker version
|
|
||||||
# - docker image build -f Dockerfile --build-arg SOURCE_TAG=$CI_COMMIT_SHA . --target output-base -t $NAME:build
|
|
||||||
|
|
||||||
# the world is not yet ready for this step
|
|
||||||
# test:
|
|
||||||
# <<: *docker-step
|
|
||||||
# commands:
|
|
||||||
# - docker run --rm -e RAILS_ENV=test -e NODE_ENV=development $NAME:build-base sh -c 'bundle config set --local without development && bundle install && rake spec'
|
|
||||||
|
|
||||||
output:
|
output:
|
||||||
<<: *docker-step
|
<<: *docker-step
|
||||||
commands:
|
commands:
|
||||||
- eval $DATE_COMMAND
|
- eval $DATE_COMMAND
|
||||||
- export TAG=$${COMMIT_DATE}.$CI_COMMIT_SHA && echo $${TAG}
|
- export TAG=$${COMMIT_DATE}.$CI_COMMIT_SHA && echo $${TAG}
|
||||||
- docker image build -f Dockerfile --build-arg SOURCE_TAG=$CI_COMMIT_SHA . -t $NAME:latest
|
- docker image build -f Dockerfile --build-arg SOURCE_TAG=$CI_COMMIT_SHA . -t $SERVER_IMAGE:$${TAG}
|
||||||
- docker image build -f streaming/Dockerfile --build-arg SOURCE_TAG=$CI_COMMIT_SHA . -t $NAME-streaming:latest
|
- docker image build -f streaming/Dockerfile --build-arg SOURCE_TAG=$CI_COMMIT_SHA . -t $STREAMING_IMAGE:$${TAG}
|
||||||
- docker tag $NAME:latest $NAME:$TAG
|
- docker tag $SERVER_IMAGE:$${TAG} $SERVER_IMAGE:latest
|
||||||
- docker tag $NAME-streaming:latest $NAME-streaming:$TAG
|
- docker tag $STREAMING_IMAGE:$${TAG} $STREAMING_IMAGE:latest
|
||||||
# idk what's actually persisted between steps
|
- echo -n > tags.txt
|
||||||
# /shrug this works, so,???
|
- echo $${TAG} | tee -a tags.txt
|
||||||
- echo $${TAG} > tags.txt
|
- echo latest | tee -a tags.txt
|
||||||
- echo latest >> tags.txt
|
|
||||||
|
|
||||||
# maybe we can use tags someday,,,
|
# maybe we can use tags someday,,,
|
||||||
# tag-tag:
|
# tag-tag:
|
||||||
|
@ -61,7 +37,7 @@ pipeline:
|
||||||
# volumes:
|
# volumes:
|
||||||
# - /var/run/docker.sock:/var/run/docker.sock
|
# - /var/run/docker.sock:/var/run/docker.sock
|
||||||
# commands:
|
# commands:
|
||||||
# - docker tag $NAME:latest $NAME:$CI_COMMIT_TAG
|
# - docker tag $SERVER_IMAGE:latest $SERVER_IMAGE:$CI_COMMIT_TAG
|
||||||
# when:
|
# when:
|
||||||
# event: tag
|
# event: tag
|
||||||
|
|
||||||
|
@ -69,10 +45,10 @@ pipeline:
|
||||||
<<: *docker-step
|
<<: *docker-step
|
||||||
commands:
|
commands:
|
||||||
- echo $REGISTRY_SECRET | docker login -u $REGISTRY_USER --password-stdin gitea.treehouse.systems
|
- echo $REGISTRY_SECRET | docker login -u $REGISTRY_USER --password-stdin gitea.treehouse.systems
|
||||||
- cat tags.txt | xargs -n 1 -I% echo docker image push $NAME:%
|
- cat tags.txt | xargs -n 1 -I% echo docker image push $SERVER_IMAGE:%
|
||||||
- cat tags.txt | xargs -n 1 -I% docker image push $NAME:%
|
- cat tags.txt | xargs -n 1 -I% docker image push $SERVER_IMAGE:%
|
||||||
- cat tags.txt | xargs -n 1 -I% echo docker image push $NAME-streaming:%
|
- cat tags.txt | xargs -n 1 -I% echo docker image push $STREAMING_IMAGE:%
|
||||||
- cat tags.txt | xargs -n 1 -I% docker image push $NAME-streaming:%
|
- cat tags.txt | xargs -n 1 -I% docker image push $STREAMING_IMAGE:%
|
||||||
when:
|
when:
|
||||||
event: [push, tag]
|
event: [push, tag]
|
||||||
branch: main
|
branch: main
|
||||||
|
|
|
@ -26,6 +26,8 @@ ARG MASTODON_VERSION_PRERELEASE=""
|
||||||
# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="something"]
|
# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="something"]
|
||||||
ARG MASTODON_VERSION_METADATA=""
|
ARG MASTODON_VERSION_METADATA=""
|
||||||
|
|
||||||
|
ARG SOURCE_TAG=""
|
||||||
|
|
||||||
# Allow Ruby on Rails to serve static files
|
# Allow Ruby on Rails to serve static files
|
||||||
# See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files
|
# See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files
|
||||||
ARG RAILS_SERVE_STATIC_FILES="true"
|
ARG RAILS_SERVE_STATIC_FILES="true"
|
||||||
|
@ -208,7 +210,7 @@ RUN \
|
||||||
# Use Ruby on Rails to create Mastodon assets
|
# Use Ruby on Rails to create Mastodon assets
|
||||||
OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder bundle exec rails assets:precompile; \
|
OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder bundle exec rails assets:precompile; \
|
||||||
# Cleanup temporary files
|
# Cleanup temporary files
|
||||||
rm -fr /opt/mastodon/tmp;
|
rm -fr /opt/mastodon/tmp
|
||||||
|
|
||||||
# Prep final Mastodon Ruby layer
|
# Prep final Mastodon Ruby layer
|
||||||
FROM ruby as mastodon
|
FROM ruby as mastodon
|
||||||
|
|
4
Gemfile
|
@ -26,7 +26,7 @@ gem 'blurhash', '~> 0.1'
|
||||||
|
|
||||||
gem 'active_model_serializers', '~> 0.10'
|
gem 'active_model_serializers', '~> 0.10'
|
||||||
gem 'addressable', '~> 2.8'
|
gem 'addressable', '~> 2.8'
|
||||||
gem 'bootsnap', '~> 1.17.0', require: false
|
gem 'bootsnap', '~> 1.18.0', require: false
|
||||||
gem 'browser'
|
gem 'browser'
|
||||||
gem 'charlock_holmes', '~> 0.7.7'
|
gem 'charlock_holmes', '~> 0.7.7'
|
||||||
gem 'chewy', '~> 7.3'
|
gem 'chewy', '~> 7.3'
|
||||||
|
@ -63,7 +63,7 @@ gem 'kaminari', '~> 1.2'
|
||||||
gem 'link_header', '~> 0.0'
|
gem 'link_header', '~> 0.0'
|
||||||
gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar'
|
gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar'
|
||||||
gem 'nokogiri', '~> 1.15'
|
gem 'nokogiri', '~> 1.15'
|
||||||
gem 'nsa', github: 'jhawthorn/nsa', ref: 'e020fcc3a54d993ab45b7194d89ab720296c111b'
|
gem 'nsa'
|
||||||
gem 'oj', '~> 3.14'
|
gem 'oj', '~> 3.14'
|
||||||
gem 'ox', '~> 2.14'
|
gem 'ox', '~> 2.14'
|
||||||
gem 'parslet'
|
gem 'parslet'
|
||||||
|
|
49
Gemfile.lock
|
@ -7,17 +7,6 @@ GIT
|
||||||
hkdf (~> 0.2)
|
hkdf (~> 0.2)
|
||||||
jwt (~> 2.0)
|
jwt (~> 2.0)
|
||||||
|
|
||||||
GIT
|
|
||||||
remote: https://github.com/jhawthorn/nsa.git
|
|
||||||
revision: e020fcc3a54d993ab45b7194d89ab720296c111b
|
|
||||||
ref: e020fcc3a54d993ab45b7194d89ab720296c111b
|
|
||||||
specs:
|
|
||||||
nsa (0.2.8)
|
|
||||||
activesupport (>= 4.2, < 7.2)
|
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
||||||
sidekiq (>= 3.5)
|
|
||||||
statsd-ruby (~> 1.4, >= 1.4.0)
|
|
||||||
|
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
|
@ -155,9 +144,9 @@ GEM
|
||||||
binding_of_caller (1.0.0)
|
binding_of_caller (1.0.0)
|
||||||
debug_inspector (>= 0.0.1)
|
debug_inspector (>= 0.0.1)
|
||||||
blurhash (0.1.7)
|
blurhash (0.1.7)
|
||||||
bootsnap (1.17.1)
|
bootsnap (1.18.3)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
brakeman (6.1.1)
|
brakeman (6.1.2)
|
||||||
racc
|
racc
|
||||||
browser (5.3.1)
|
browser (5.3.1)
|
||||||
brpoplpush-redis_script (0.1.3)
|
brpoplpush-redis_script (0.1.3)
|
||||||
|
@ -167,11 +156,11 @@ GEM
|
||||||
bundler-audit (0.9.1)
|
bundler-audit (0.9.1)
|
||||||
bundler (>= 1.2.0, < 3)
|
bundler (>= 1.2.0, < 3)
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
capybara (3.39.2)
|
capybara (3.40.0)
|
||||||
addressable
|
addressable
|
||||||
matrix
|
matrix
|
||||||
mini_mime (>= 0.1.3)
|
mini_mime (>= 0.1.3)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.11)
|
||||||
rack (>= 1.6.0)
|
rack (>= 1.6.0)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
regexp_parser (>= 1.5, < 3.0)
|
regexp_parser (>= 1.5, < 3.0)
|
||||||
|
@ -180,7 +169,7 @@ GEM
|
||||||
activesupport
|
activesupport
|
||||||
cbor (0.5.9.6)
|
cbor (0.5.9.6)
|
||||||
charlock_holmes (0.7.7)
|
charlock_holmes (0.7.7)
|
||||||
chewy (7.5.0)
|
chewy (7.5.1)
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
elasticsearch (>= 7.12.0, < 7.14.0)
|
elasticsearch (>= 7.12.0, < 7.14.0)
|
||||||
elasticsearch-dsl
|
elasticsearch-dsl
|
||||||
|
@ -193,7 +182,8 @@ GEM
|
||||||
cose (1.3.0)
|
cose (1.3.0)
|
||||||
cbor (~> 0.5.9)
|
cbor (~> 0.5.9)
|
||||||
openssl-signature_algorithm (~> 1.0)
|
openssl-signature_algorithm (~> 1.0)
|
||||||
crack (0.4.5)
|
crack (0.4.6)
|
||||||
|
bigdecimal
|
||||||
rexml
|
rexml
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
css_parser (1.14.0)
|
css_parser (1.14.0)
|
||||||
|
@ -320,13 +310,13 @@ GEM
|
||||||
activesupport (>= 5.1)
|
activesupport (>= 5.1)
|
||||||
haml (>= 4.0.6)
|
haml (>= 4.0.6)
|
||||||
railties (>= 5.1)
|
railties (>= 5.1)
|
||||||
haml_lint (0.55.0)
|
haml_lint (0.56.0)
|
||||||
haml (>= 5.0)
|
haml (>= 5.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
rainbow
|
rainbow
|
||||||
rubocop (>= 1.0)
|
rubocop (>= 1.0)
|
||||||
sysexits (~> 1.1)
|
sysexits (~> 1.1)
|
||||||
hashdiff (1.0.1)
|
hashdiff (1.1.0)
|
||||||
hashie (5.0.0)
|
hashie (5.0.0)
|
||||||
hcaptcha (7.1.0)
|
hcaptcha (7.1.0)
|
||||||
json
|
json
|
||||||
|
@ -362,7 +352,7 @@ GEM
|
||||||
terminal-table (>= 1.5.1)
|
terminal-table (>= 1.5.1)
|
||||||
idn-ruby (0.1.5)
|
idn-ruby (0.1.5)
|
||||||
io-console (0.7.2)
|
io-console (0.7.2)
|
||||||
irb (1.11.1)
|
irb (1.11.2)
|
||||||
rdoc
|
rdoc
|
||||||
reline (>= 0.4.2)
|
reline (>= 0.4.2)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
|
@ -466,9 +456,14 @@ GEM
|
||||||
net-smtp (0.4.0.1)
|
net-smtp (0.4.0.1)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.5.9)
|
nio4r (2.5.9)
|
||||||
nokogiri (1.16.0)
|
nokogiri (1.16.2)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
|
nsa (0.3.0)
|
||||||
|
activesupport (>= 4.2, < 7.2)
|
||||||
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
|
sidekiq (>= 3.5)
|
||||||
|
statsd-ruby (~> 1.4, >= 1.4.0)
|
||||||
oj (3.16.3)
|
oj (3.16.3)
|
||||||
bigdecimal (>= 3.0)
|
bigdecimal (>= 3.0)
|
||||||
omniauth (2.1.1)
|
omniauth (2.1.1)
|
||||||
|
@ -512,7 +507,7 @@ GEM
|
||||||
pastel (0.8.0)
|
pastel (0.8.0)
|
||||||
tty-color (~> 0.5)
|
tty-color (~> 0.5)
|
||||||
pg (1.5.4)
|
pg (1.5.4)
|
||||||
pghero (3.4.0)
|
pghero (3.4.1)
|
||||||
activerecord (>= 6)
|
activerecord (>= 6)
|
||||||
posix-spawn (0.3.15)
|
posix-spawn (0.3.15)
|
||||||
premailer (1.21.0)
|
premailer (1.21.0)
|
||||||
|
@ -713,7 +708,7 @@ GEM
|
||||||
rufus-scheduler (~> 3.2)
|
rufus-scheduler (~> 3.2)
|
||||||
sidekiq (>= 6, < 8)
|
sidekiq (>= 6, < 8)
|
||||||
tilt (>= 1.4.0)
|
tilt (>= 1.4.0)
|
||||||
sidekiq-unique-jobs (7.1.31)
|
sidekiq-unique-jobs (7.1.33)
|
||||||
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
|
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.5)
|
concurrent-ruby (~> 1.0, >= 1.0.5)
|
||||||
redis (< 5.0)
|
redis (< 5.0)
|
||||||
|
@ -772,7 +767,7 @@ GEM
|
||||||
unf (~> 0.1.0)
|
unf (~> 0.1.0)
|
||||||
tzinfo (2.0.6)
|
tzinfo (2.0.6)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
tzinfo-data (1.2023.4)
|
tzinfo-data (1.2024.1)
|
||||||
tzinfo (>= 1.0.0)
|
tzinfo (>= 1.0.0)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
|
@ -799,7 +794,7 @@ GEM
|
||||||
webfinger (1.2.0)
|
webfinger (1.2.0)
|
||||||
activesupport
|
activesupport
|
||||||
httpclient (>= 2.4)
|
httpclient (>= 2.4)
|
||||||
webmock (3.19.1)
|
webmock (3.20.0)
|
||||||
addressable (>= 2.8.0)
|
addressable (>= 2.8.0)
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
hashdiff (>= 0.4.0, < 2.0.0)
|
hashdiff (>= 0.4.0, < 2.0.0)
|
||||||
|
@ -830,7 +825,7 @@ DEPENDENCIES
|
||||||
better_errors (~> 2.9)
|
better_errors (~> 2.9)
|
||||||
binding_of_caller (~> 1.0)
|
binding_of_caller (~> 1.0)
|
||||||
blurhash (~> 0.1)
|
blurhash (~> 0.1)
|
||||||
bootsnap (~> 1.17.0)
|
bootsnap (~> 1.18.0)
|
||||||
brakeman (~> 6.0)
|
brakeman (~> 6.0)
|
||||||
browser
|
browser
|
||||||
bundler-audit (~> 0.9)
|
bundler-audit (~> 0.9)
|
||||||
|
@ -888,7 +883,7 @@ DEPENDENCIES
|
||||||
net-http (~> 0.4.0)
|
net-http (~> 0.4.0)
|
||||||
net-ldap (~> 0.18)
|
net-ldap (~> 0.18)
|
||||||
nokogiri (~> 1.15)
|
nokogiri (~> 1.15)
|
||||||
nsa!
|
nsa
|
||||||
oj (~> 3.14)
|
oj (~> 3.14)
|
||||||
omniauth (~> 2.0)
|
omniauth (~> 2.0)
|
||||||
omniauth-cas (~> 3.0.0.beta.1)
|
omniauth-cas (~> 3.0.0.beta.1)
|
||||||
|
|
|
@ -2,4 +2,3 @@ web: env PORT=3000 RAILS_ENV=development bundle exec puma -C config/puma.rb
|
||||||
sidekiq: env PORT=3000 RAILS_ENV=development bundle exec sidekiq
|
sidekiq: env PORT=3000 RAILS_ENV=development bundle exec sidekiq
|
||||||
stream: env PORT=4000 yarn workspace @mastodon/streaming start
|
stream: env PORT=4000 yarn workspace @mastodon/streaming start
|
||||||
webpack: bin/webpack-dev-server
|
webpack: bin/webpack-dev-server
|
||||||
caddy: caddy run
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class Api::V1::Statuses::ReactionsController < Api::V1::Statuses::BaseController
|
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:favourites' }
|
|
||||||
before_action :require_user!
|
|
||||||
|
|
||||||
def create
|
|
||||||
ReactService.new.call(current_account, @status, params[:id])
|
|
||||||
render json: @status, serializer: REST::StatusSerializer
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy
|
|
||||||
UnreactWorker.perform_async(current_account.id, @status.id, params[:id])
|
|
||||||
|
|
||||||
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, reactions_map: { @status.id => false })
|
|
||||||
rescue Mastodon::NotPermittedError
|
|
||||||
not_found
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -7,7 +7,7 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||||
def self.provides_callback_for(provider)
|
def self.provides_callback_for(provider)
|
||||||
define_method provider do
|
define_method provider do
|
||||||
@provider = provider
|
@provider = provider
|
||||||
@user = User.find_for_oauth(request.env['omniauth.auth'], current_user)
|
@user = User.find_for_omniauth(request.env['omniauth.auth'], current_user)
|
||||||
|
|
||||||
if @user.persisted?
|
if @user.persisted?
|
||||||
record_login_activity
|
record_login_activity
|
||||||
|
|
|
@ -51,16 +51,6 @@ export const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST';
|
||||||
export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS';
|
export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS';
|
||||||
export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL';
|
export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL';
|
||||||
|
|
||||||
export const REACTION_UPDATE = 'REACTION_UPDATE';
|
|
||||||
|
|
||||||
export const REACTION_ADD_REQUEST = 'REACTION_ADD_REQUEST';
|
|
||||||
export const REACTION_ADD_SUCCESS = 'REACTION_ADD_SUCCESS';
|
|
||||||
export const REACTION_ADD_FAIL = 'REACTION_ADD_FAIL';
|
|
||||||
|
|
||||||
export const REACTION_REMOVE_REQUEST = 'REACTION_REMOVE_REQUEST';
|
|
||||||
export const REACTION_REMOVE_SUCCESS = 'REACTION_REMOVE_SUCCESS';
|
|
||||||
export const REACTION_REMOVE_FAIL = 'REACTION_REMOVE_FAIL';
|
|
||||||
|
|
||||||
export function reblog(status, visibility) {
|
export function reblog(status, visibility) {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
dispatch(reblogRequest(status));
|
dispatch(reblogRequest(status));
|
||||||
|
@ -526,75 +516,3 @@ export function unpinFail(status, error) {
|
||||||
skipLoading: true,
|
skipLoading: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const addReaction = (statusId, name, url) => (dispatch, getState) => {
|
|
||||||
const status = getState().get('statuses').get(statusId);
|
|
||||||
let alreadyAdded = false;
|
|
||||||
if (status) {
|
|
||||||
const reaction = status.get('reactions').find(x => x.get('name') === name);
|
|
||||||
if (reaction && reaction.get('me')) {
|
|
||||||
alreadyAdded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!alreadyAdded) {
|
|
||||||
dispatch(addReactionRequest(statusId, name, url));
|
|
||||||
}
|
|
||||||
|
|
||||||
// encodeURIComponent is required for the Keycap Number Sign emoji, see:
|
|
||||||
// <https://github.com/glitch-soc/mastodon/pull/1980#issuecomment-1345538932>
|
|
||||||
api(getState).post(`/api/v1/statuses/${statusId}/react/${encodeURIComponent(name)}`).then(() => {
|
|
||||||
dispatch(addReactionSuccess(statusId, name));
|
|
||||||
}).catch(err => {
|
|
||||||
if (!alreadyAdded) {
|
|
||||||
dispatch(addReactionFail(statusId, name, err));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addReactionRequest = (statusId, name, url) => ({
|
|
||||||
type: REACTION_ADD_REQUEST,
|
|
||||||
id: statusId,
|
|
||||||
name,
|
|
||||||
url,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addReactionSuccess = (statusId, name) => ({
|
|
||||||
type: REACTION_ADD_SUCCESS,
|
|
||||||
id: statusId,
|
|
||||||
name,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addReactionFail = (statusId, name, error) => ({
|
|
||||||
type: REACTION_ADD_FAIL,
|
|
||||||
id: statusId,
|
|
||||||
name,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeReaction = (statusId, name) => (dispatch, getState) => {
|
|
||||||
dispatch(removeReactionRequest(statusId, name));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/statuses/${statusId}/unreact/${encodeURIComponent(name)}`).then(() => {
|
|
||||||
dispatch(removeReactionSuccess(statusId, name));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(removeReactionFail(statusId, name, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeReactionRequest = (statusId, name) => ({
|
|
||||||
type: REACTION_REMOVE_REQUEST,
|
|
||||||
id: statusId,
|
|
||||||
name,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeReactionSuccess = (statusId, name) => ({
|
|
||||||
type: REACTION_REMOVE_SUCCESS,
|
|
||||||
id: statusId,
|
|
||||||
name,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeReactionFail = (statusId, name) => ({
|
|
||||||
type: REACTION_REMOVE_FAIL,
|
|
||||||
id: statusId,
|
|
||||||
name,
|
|
||||||
});
|
|
||||||
|
|
|
@ -142,7 +142,6 @@ const excludeTypesFromFilter = filter => {
|
||||||
'follow',
|
'follow',
|
||||||
'follow_request',
|
'follow_request',
|
||||||
'favourite',
|
'favourite',
|
||||||
'reaction',
|
|
||||||
'reblog',
|
'reblog',
|
||||||
'mention',
|
'mention',
|
||||||
'poll',
|
'poll',
|
||||||
|
|
|
@ -20,7 +20,7 @@ import Card from '../features/status/components/card';
|
||||||
// to use the progress bar to show download progress
|
// to use the progress bar to show download progress
|
||||||
import Bundle from '../features/ui/components/bundle';
|
import Bundle from '../features/ui/components/bundle';
|
||||||
import { MediaGallery, Video, Audio } from '../features/ui/util/async-components';
|
import { MediaGallery, Video, Audio } from '../features/ui/util/async-components';
|
||||||
import { displayMedia, visibleReactions } from '../initial_state';
|
import { displayMedia } from '../initial_state';
|
||||||
|
|
||||||
import AttachmentList from './attachment_list';
|
import AttachmentList from './attachment_list';
|
||||||
import { getHashtagBarForStatus } from './hashtag_bar';
|
import { getHashtagBarForStatus } from './hashtag_bar';
|
||||||
|
@ -29,7 +29,6 @@ import StatusContent from './status_content';
|
||||||
import StatusHeader from './status_header';
|
import StatusHeader from './status_header';
|
||||||
import StatusIcons from './status_icons';
|
import StatusIcons from './status_icons';
|
||||||
import StatusPrepend from './status_prepend';
|
import StatusPrepend from './status_prepend';
|
||||||
import StatusReactions from './status_reactions';
|
|
||||||
|
|
||||||
const domParser = new DOMParser();
|
const domParser = new DOMParser();
|
||||||
|
|
||||||
|
@ -72,10 +71,6 @@ export const defaultMediaVisibility = (status, settings) => {
|
||||||
|
|
||||||
class Status extends ImmutablePureComponent {
|
class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
containerId: PropTypes.string,
|
containerId: PropTypes.string,
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
|
@ -93,8 +88,6 @@ class Status extends ImmutablePureComponent {
|
||||||
onDelete: PropTypes.func,
|
onDelete: PropTypes.func,
|
||||||
onDirect: PropTypes.func,
|
onDirect: PropTypes.func,
|
||||||
onMention: PropTypes.func,
|
onMention: PropTypes.func,
|
||||||
onReactionAdd: PropTypes.func,
|
|
||||||
onReactionRemove: PropTypes.func,
|
|
||||||
onPin: PropTypes.func,
|
onPin: PropTypes.func,
|
||||||
onOpenMedia: PropTypes.func,
|
onOpenMedia: PropTypes.func,
|
||||||
onOpenVideo: PropTypes.func,
|
onOpenVideo: PropTypes.func,
|
||||||
|
@ -759,7 +752,6 @@ class Status extends ImmutablePureComponent {
|
||||||
if (this.props.prepend && account) {
|
if (this.props.prepend && account) {
|
||||||
const notifKind = {
|
const notifKind = {
|
||||||
favourite: 'favourited',
|
favourite: 'favourited',
|
||||||
reaction: 'reacted',
|
|
||||||
reblog: 'boosted',
|
reblog: 'boosted',
|
||||||
reblogged_by: 'boosted',
|
reblogged_by: 'boosted',
|
||||||
status: 'posted',
|
status: 'posted',
|
||||||
|
@ -846,15 +838,6 @@ class Status extends ImmutablePureComponent {
|
||||||
{...statusContentProps}
|
{...statusContentProps}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<StatusReactions
|
|
||||||
statusId={status.get('id')}
|
|
||||||
reactions={status.get('reactions')}
|
|
||||||
numVisible={visibleReactions}
|
|
||||||
addReaction={this.props.onReactionAdd}
|
|
||||||
removeReaction={this.props.onReactionRemove}
|
|
||||||
canReact={this.context.identity.signedIn}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{!isCollapsed || !(muted || !settings.getIn(['collapsed', 'show_action_bar'])) ? (
|
{!isCollapsed || !(muted || !settings.getIn(['collapsed', 'show_action_bar'])) ? (
|
||||||
<StatusActionBar
|
<StatusActionBar
|
||||||
status={status}
|
status={status}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { withRouter } from 'react-router-dom';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
import AddReactionIcon from '@/material-icons/400-24px/add_reaction.svg?react';
|
|
||||||
import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg?react';
|
import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg?react';
|
||||||
import BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react';
|
import BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react';
|
||||||
import FormatQuoteIcon from '@/material-icons/400-24px/format_quote-fill.svg?react';
|
import FormatQuoteIcon from '@/material-icons/400-24px/format_quote-fill.svg?react';
|
||||||
|
@ -28,8 +27,7 @@ import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend
|
||||||
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
|
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
|
||||||
|
|
||||||
import DropdownMenuContainer from '../containers/dropdown_menu_container';
|
import DropdownMenuContainer from '../containers/dropdown_menu_container';
|
||||||
import EmojiPickerDropdown from '../features/compose/containers/emoji_picker_dropdown_container';
|
import { me } from '../initial_state';
|
||||||
import { me, maxReactions } from '../initial_state';
|
|
||||||
|
|
||||||
import { IconButton } from './icon_button';
|
import { IconButton } from './icon_button';
|
||||||
import { RelativeTimestamp } from './relative_timestamp';
|
import { RelativeTimestamp } from './relative_timestamp';
|
||||||
|
@ -52,7 +50,6 @@ const messages = defineMessages({
|
||||||
cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
|
cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
|
||||||
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
|
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
|
||||||
favourite: { id: 'status.favourite', defaultMessage: 'Favorite' },
|
favourite: { id: 'status.favourite', defaultMessage: 'Favorite' },
|
||||||
react: { id: 'status.react', defaultMessage: 'React' },
|
|
||||||
bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' },
|
bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' },
|
||||||
open: { id: 'status.open', defaultMessage: 'Expand this status' },
|
open: { id: 'status.open', defaultMessage: 'Expand this status' },
|
||||||
report: { id: 'status.report', defaultMessage: 'Report @{name}' },
|
report: { id: 'status.report', defaultMessage: 'Report @{name}' },
|
||||||
|
@ -81,7 +78,6 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
onReply: PropTypes.func,
|
onReply: PropTypes.func,
|
||||||
onFavourite: PropTypes.func,
|
onFavourite: PropTypes.func,
|
||||||
onReactionAdd: PropTypes.func,
|
|
||||||
onReblog: PropTypes.func,
|
onReblog: PropTypes.func,
|
||||||
onQuote: PropTypes.func,
|
onQuote: PropTypes.func,
|
||||||
onDelete: PropTypes.func,
|
onDelete: PropTypes.func,
|
||||||
|
@ -151,10 +147,6 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleEmojiPick = data => {
|
|
||||||
this.props.onReactionAdd(this.props.status.get('id'), data.native.replace(/:/g, ''), data.imageUrl);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleReblogClick = e => {
|
handleReblogClick = e => {
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.context.identity;
|
||||||
|
|
||||||
|
@ -230,8 +222,6 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
this.props.onAddFilter(this.props.status);
|
this.props.onAddFilter(this.props.status);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleNoOp = () => {}; // hack for reaction add button
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { status, intl, withDismiss, withCounters, showReplyCount, scrollKey } = this.props;
|
const { status, intl, withDismiss, withCounters, showReplyCount, scrollKey } = this.props;
|
||||||
const { permissions, signedIn } = this.context.identity;
|
const { permissions, signedIn } = this.context.identity;
|
||||||
|
@ -360,18 +350,6 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
<IconButton className='status__action-bar-button' title={intl.formatMessage(messages.hide)} icon='eye' iconComponent={VisibilityIcon} onClick={this.handleHideClick} />
|
<IconButton className='status__action-bar-button' title={intl.formatMessage(messages.hide)} icon='eye' iconComponent={VisibilityIcon} onClick={this.handleHideClick} />
|
||||||
);
|
);
|
||||||
|
|
||||||
const canReact = permissions && status.get('reactions').filter(r => r.get('count') > 0 && r.get('me')).size < maxReactions;
|
|
||||||
const reactButton = (
|
|
||||||
<IconButton
|
|
||||||
className='status__action-bar-button'
|
|
||||||
onClick={this.handleNoOp} // EmojiPickerDropdown handles that
|
|
||||||
title={intl.formatMessage(messages.react)}
|
|
||||||
disabled={!canReact}
|
|
||||||
icon='add_reaction'
|
|
||||||
iconComponent={AddReactionIcon}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='status__action-bar'>
|
<div className='status__action-bar'>
|
||||||
<IconButton
|
<IconButton
|
||||||
|
@ -388,11 +366,6 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} /* active={status.get('reblogged')} */ title={quoteTitle} icon={quoteIcon} iconComponent={quoteIconComponent} onClick={this.handleQuoteClick} />
|
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} /* active={status.get('reblogged')} */ title={quoteTitle} icon={quoteIcon} iconComponent={quoteIconComponent} onClick={this.handleQuoteClick} />
|
||||||
|
|
||||||
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
|
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
|
||||||
{
|
|
||||||
permissions
|
|
||||||
? <EmojiPickerDropdown className='status__action-bar-button' onPickEmoji={this.handleEmojiPick} button={reactButton} disabled={!canReact} />
|
|
||||||
: reactButton
|
|
||||||
}
|
|
||||||
<IconButton className='status__action-bar-button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} />
|
<IconButton className='status__action-bar-button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} />
|
||||||
|
|
||||||
{filterButton}
|
{filterButton}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
|
||||||
import AddReactionIcon from '@/material-icons/400-24px/add_reaction.svg?react';
|
|
||||||
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
|
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
|
||||||
import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
||||||
import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react';
|
import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react';
|
||||||
|
@ -67,14 +66,6 @@ export default class StatusPrepend extends PureComponent {
|
||||||
values={{ name : link }}
|
values={{ name : link }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'reaction':
|
|
||||||
return (
|
|
||||||
<FormattedMessage
|
|
||||||
id='notification.reaction'
|
|
||||||
defaultMessage='{name} reacted to your status'
|
|
||||||
values={{ name: link }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'reblog':
|
case 'reblog':
|
||||||
return (
|
return (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
@ -130,10 +121,6 @@ export default class StatusPrepend extends PureComponent {
|
||||||
iconId = 'star';
|
iconId = 'star';
|
||||||
iconComponent = StarIcon;
|
iconComponent = StarIcon;
|
||||||
break;
|
break;
|
||||||
case 'reaction':
|
|
||||||
iconId = 'add_reaction';
|
|
||||||
iconComponent = AddReactionIcon;
|
|
||||||
break;
|
|
||||||
case 'featured':
|
case 'featured':
|
||||||
iconId = 'thumb-tack';
|
iconId = 'thumb-tack';
|
||||||
iconComponent = PushPinIcon;
|
iconComponent = PushPinIcon;
|
||||||
|
|
|
@ -1,175 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
|
|
||||||
import TransitionMotion from 'react-motion/lib/TransitionMotion';
|
|
||||||
import spring from 'react-motion/lib/spring';
|
|
||||||
|
|
||||||
import { unicodeMapping } from '../features/emoji/emoji_unicode_mapping_light';
|
|
||||||
import { autoPlayGif, reduceMotion } from '../initial_state';
|
|
||||||
import { assetHost } from '../utils/config';
|
|
||||||
|
|
||||||
import { AnimatedNumber } from './animated_number';
|
|
||||||
|
|
||||||
export default class StatusReactions extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
statusId: PropTypes.string.isRequired,
|
|
||||||
reactions: ImmutablePropTypes.list.isRequired,
|
|
||||||
numVisible: PropTypes.number,
|
|
||||||
addReaction: PropTypes.func.isRequired,
|
|
||||||
canReact: PropTypes.bool.isRequired,
|
|
||||||
removeReaction: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
willEnter() {
|
|
||||||
return { scale: reduceMotion ? 1 : 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
willLeave() {
|
|
||||||
return { scale: reduceMotion ? 0 : spring(0, { stiffness: 170, damping: 26 }) };
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { reactions, numVisible } = this.props;
|
|
||||||
let visibleReactions = reactions
|
|
||||||
.filter(x => x.get('count') > 0)
|
|
||||||
.sort((a, b) => b.get('count') - a.get('count'));
|
|
||||||
|
|
||||||
if (numVisible >= 0) {
|
|
||||||
visibleReactions = visibleReactions.filter((_, i) => i < numVisible);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = visibleReactions.map(reaction => ({
|
|
||||||
key: reaction.get('name'),
|
|
||||||
data: reaction,
|
|
||||||
style: { scale: reduceMotion ? 1 : spring(1, { stiffness: 150, damping: 13 }) },
|
|
||||||
})).toArray();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TransitionMotion styles={styles} willEnter={this.willEnter} willLeave={this.willLeave}>
|
|
||||||
{items => (
|
|
||||||
<div className={classNames('reactions-bar', { 'reactions-bar--empty': visibleReactions.isEmpty() })}>
|
|
||||||
{items.map(({ key, data, style }) => (
|
|
||||||
<Reaction
|
|
||||||
key={key}
|
|
||||||
statusId={this.props.statusId}
|
|
||||||
reaction={data}
|
|
||||||
style={{ transform: `scale(${style.scale})`, position: style.scale < 0.5 ? 'absolute' : 'static' }}
|
|
||||||
addReaction={this.props.addReaction}
|
|
||||||
removeReaction={this.props.removeReaction}
|
|
||||||
canReact={this.props.canReact}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</TransitionMotion>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class Reaction extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
statusId: PropTypes.string,
|
|
||||||
reaction: ImmutablePropTypes.map.isRequired,
|
|
||||||
addReaction: PropTypes.func.isRequired,
|
|
||||||
removeReaction: PropTypes.func.isRequired,
|
|
||||||
canReact: PropTypes.bool.isRequired,
|
|
||||||
style: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
hovered: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
handleClick = () => {
|
|
||||||
const { reaction, statusId, addReaction, removeReaction } = this.props;
|
|
||||||
|
|
||||||
if (reaction.get('me')) {
|
|
||||||
removeReaction(statusId, reaction.get('name'));
|
|
||||||
} else {
|
|
||||||
addReaction(statusId, reaction.get('name'));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMouseEnter = () => this.setState({ hovered: true });
|
|
||||||
|
|
||||||
handleMouseLeave = () => this.setState({ hovered: false });
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { reaction } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
className={classNames('reactions-bar__item', { active: reaction.get('me') })}
|
|
||||||
onClick={this.handleClick}
|
|
||||||
onMouseEnter={this.handleMouseEnter}
|
|
||||||
onMouseLeave={this.handleMouseLeave}
|
|
||||||
disabled={!this.props.canReact}
|
|
||||||
style={this.props.style}
|
|
||||||
>
|
|
||||||
<span className='reactions-bar__item__emoji'>
|
|
||||||
<Emoji
|
|
||||||
hovered={this.state.hovered}
|
|
||||||
emoji={reaction.get('name')}
|
|
||||||
url={reaction.get('url')}
|
|
||||||
staticUrl={reaction.get('static_url')}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span className='reactions-bar__item__count'>
|
|
||||||
<AnimatedNumber value={reaction.get('count')} />
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class Emoji extends React.PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
emoji: PropTypes.string.isRequired,
|
|
||||||
hovered: PropTypes.bool.isRequired,
|
|
||||||
url: PropTypes.string,
|
|
||||||
staticUrl: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { emoji, hovered, url, staticUrl } = this.props;
|
|
||||||
|
|
||||||
if (unicodeMapping[emoji]) {
|
|
||||||
const { filename, shortCode } = unicodeMapping[this.props.emoji];
|
|
||||||
const title = shortCode ? `:${shortCode}:` : '';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<img
|
|
||||||
draggable='false'
|
|
||||||
className='emojione'
|
|
||||||
alt={emoji}
|
|
||||||
title={title}
|
|
||||||
src={`${assetHost}/emoji/${filename}.svg`}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const filename = (autoPlayGif || hovered) ? url : staticUrl;
|
|
||||||
const shortCode = `:${emoji}:`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<img
|
|
||||||
draggable='false'
|
|
||||||
className='emojione custom-emoji'
|
|
||||||
alt={shortCode}
|
|
||||||
title={shortCode}
|
|
||||||
src={filename}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -22,8 +22,6 @@ import {
|
||||||
unbookmark,
|
unbookmark,
|
||||||
pin,
|
pin,
|
||||||
unpin,
|
unpin,
|
||||||
addReaction,
|
|
||||||
removeReaction,
|
|
||||||
} from 'flavours/glitch/actions/interactions';
|
} from 'flavours/glitch/actions/interactions';
|
||||||
import { changeLocalSetting } from 'flavours/glitch/actions/local_settings';
|
import { changeLocalSetting } from 'flavours/glitch/actions/local_settings';
|
||||||
import { openModal } from 'flavours/glitch/actions/modal';
|
import { openModal } from 'flavours/glitch/actions/modal';
|
||||||
|
@ -198,14 +196,6 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onReactionAdd (statusId, name, url) {
|
|
||||||
dispatch(addReaction(statusId, name, url));
|
|
||||||
},
|
|
||||||
|
|
||||||
onReactionRemove (statusId, name) {
|
|
||||||
dispatch(removeReaction(statusId, name));
|
|
||||||
},
|
|
||||||
|
|
||||||
onEmbed (status) {
|
onEmbed (status) {
|
||||||
dispatch(openModal({
|
dispatch(openModal({
|
||||||
modalType: 'EMBED',
|
modalType: 'EMBED',
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default class AutosuggestAccount extends ImmutablePureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='autosuggest-account' title={account.get('acct')}>
|
<div className='autosuggest-account' title={account.get('acct')}>
|
||||||
<div className='autosuggest-account-icon'><Avatar account={account} size={24} /></div>
|
<div className='autosuggest-account-icon'><Avatar account={account} size={18} /></div>
|
||||||
<DisplayName account={account} inline />
|
<DisplayName account={account} inline />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -71,7 +71,6 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
singleColumn: PropTypes.bool,
|
singleColumn: PropTypes.bool,
|
||||||
lang: PropTypes.string,
|
lang: PropTypes.string,
|
||||||
advancedOptions: ImmutablePropTypes.map,
|
advancedOptions: ImmutablePropTypes.map,
|
||||||
layout: PropTypes.string,
|
|
||||||
media: ImmutablePropTypes.list,
|
media: ImmutablePropTypes.list,
|
||||||
sideArm: PropTypes.string,
|
sideArm: PropTypes.string,
|
||||||
sensitive: PropTypes.bool,
|
sensitive: PropTypes.bool,
|
||||||
|
@ -260,7 +259,6 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
intl,
|
intl,
|
||||||
advancedOptions,
|
advancedOptions,
|
||||||
isSubmitting,
|
isSubmitting,
|
||||||
layout,
|
|
||||||
onChangeSpoilerness,
|
onChangeSpoilerness,
|
||||||
onPaste,
|
onPaste,
|
||||||
privacy,
|
privacy,
|
||||||
|
@ -315,7 +313,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||||
onSuggestionSelected={this.onSuggestionSelected}
|
onSuggestionSelected={this.onSuggestionSelected}
|
||||||
onPaste={onPaste}
|
onPaste={onPaste}
|
||||||
autoFocus={!showSearch && !isMobile(window.innerWidth, layout)}
|
autoFocus={!showSearch && !isMobile(window.innerWidth)}
|
||||||
lang={this.props.lang}
|
lang={this.props.lang}
|
||||||
>
|
>
|
||||||
<TextareaIcons advancedOptions={advancedOptions} />
|
<TextareaIcons advancedOptions={advancedOptions} />
|
||||||
|
|
|
@ -324,7 +324,6 @@ class EmojiPickerDropdown extends PureComponent {
|
||||||
onSkinTone: PropTypes.func.isRequired,
|
onSkinTone: PropTypes.func.isRequired,
|
||||||
skinTone: PropTypes.number.isRequired,
|
skinTone: PropTypes.number.isRequired,
|
||||||
button: PropTypes.node,
|
button: PropTypes.node,
|
||||||
disabled: PropTypes.bool,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
@ -358,7 +357,7 @@ class EmojiPickerDropdown extends PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
onToggle = (e) => {
|
onToggle = (e) => {
|
||||||
if (!this.state.disabled && !this.state.loading && (!e.key || e.key === 'Enter')) {
|
if (!this.state.loading && (!e.key || e.key === 'Enter')) {
|
||||||
if (this.state.active) {
|
if (this.state.active) {
|
||||||
this.onHideDropdown();
|
this.onHideDropdown();
|
||||||
} else {
|
} else {
|
||||||
|
@ -396,7 +395,7 @@ class EmojiPickerDropdown extends PureComponent {
|
||||||
/>}
|
/>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Overlay show={active} placement={'bottom'} flip target={this.findTarget} popperConfig={{ strategy: 'fixed' }}>
|
<Overlay show={active} placement={'bottom'} target={this.findTarget} popperConfig={{ strategy: 'fixed' }}>
|
||||||
{({ props, placement })=> (
|
{({ props, placement })=> (
|
||||||
<div {...props} style={{ ...props.style, width: 299 }}>
|
<div {...props} style={{ ...props.style, width: 299 }}>
|
||||||
<div className={`dropdown-animation ${placement}`}>
|
<div className={`dropdown-animation ${placement}`}>
|
||||||
|
|
|
@ -38,8 +38,8 @@ export default class NavigationBar extends ImmutablePureComponent {
|
||||||
|
|
||||||
{ profileLink !== undefined && (
|
{ profileLink !== undefined && (
|
||||||
<a
|
<a
|
||||||
className='edit'
|
|
||||||
href={profileLink}
|
href={profileLink}
|
||||||
|
className='navigation-bar__profile-edit'
|
||||||
><FormattedMessage id='navigation_bar.edit_profile' defaultMessage='Edit profile' /></a>
|
><FormattedMessage id='navigation_bar.edit_profile' defaultMessage='Edit profile' /></a>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -76,7 +76,7 @@ class SearchResults extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='drawer--results'>
|
<div className='search-results'>
|
||||||
<header className='search-results__header'>
|
<header className='search-results__header'>
|
||||||
<Icon id='search' icon={SearchIcon} />
|
<Icon id='search' icon={SearchIcon} />
|
||||||
<FormattedMessage id='explore.search_results' defaultMessage='Search results' />
|
<FormattedMessage id='explore.search_results' defaultMessage='Search results' />
|
||||||
|
|
|
@ -71,7 +71,6 @@ const mapStateToProps = state => ({
|
||||||
isInReply: state.getIn(['compose', 'in_reply_to']) !== null,
|
isInReply: state.getIn(['compose', 'in_reply_to']) !== null,
|
||||||
lang: state.getIn(['compose', 'language']),
|
lang: state.getIn(['compose', 'language']),
|
||||||
advancedOptions: state.getIn(['compose', 'advanced_options']),
|
advancedOptions: state.getIn(['compose', 'advanced_options']),
|
||||||
layout: state.getIn(['local_settings', 'layout']),
|
|
||||||
media: state.getIn(['compose', 'media_attachments']),
|
media: state.getIn(['compose', 'media_attachments']),
|
||||||
sideArm: sideArmPrivacy(state),
|
sideArm: sideArmPrivacy(state),
|
||||||
sensitive: state.getIn(['compose', 'sensitive']),
|
sensitive: state.getIn(['compose', 'sensitive']),
|
||||||
|
|
|
@ -9,6 +9,8 @@ import { NonceProvider } from 'react-select';
|
||||||
import AsyncSelect from 'react-select/async';
|
import AsyncSelect from 'react-select/async';
|
||||||
import Toggle from 'react-toggle';
|
import Toggle from 'react-toggle';
|
||||||
|
|
||||||
|
import { maxFeedHashtags } from 'flavours/glitch/initial_state';
|
||||||
|
|
||||||
import SettingToggle from '../../notifications/components/setting_toggle';
|
import SettingToggle from '../../notifications/components/setting_toggle';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
@ -46,9 +48,9 @@ class ColumnSettings extends PureComponent {
|
||||||
onSelect = mode => value => {
|
onSelect = mode => value => {
|
||||||
const oldValue = this.tags(mode);
|
const oldValue = this.tags(mode);
|
||||||
|
|
||||||
// Prevent changes that add more than 4 tags, but allow removing
|
// Prevent changes that add more than the number of configured
|
||||||
// tags that were already added before
|
// tags, but allow removing tags that were already added before
|
||||||
if ((value.length > 4) && !(value < oldValue)) {
|
if ((value.length > maxFeedHashtags) && !(value < oldValue)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ class NewListForm extends PureComponent {
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
disabled={disabled || !value}
|
disabled={disabled || !value}
|
||||||
title={title}
|
text={title}
|
||||||
onClick={this.handleClick}
|
onClick={this.handleClick}
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -120,17 +120,6 @@ export default class ColumnSettings extends PureComponent {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div role='group' aria-labelledby='notifications-reaction'>
|
|
||||||
<span id='notifications-reaction' className='column-settings__section'><FormattedMessage id='notifications.column_settings.reaction' defaultMessage='Reactions:' /></span>
|
|
||||||
|
|
||||||
<div className='column-settings__pillbar'>
|
|
||||||
<PillBarButton disabled={browserPermission === 'denied'} prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'reaction']} onChange={onChange} label={alertStr} />
|
|
||||||
{showPushSettings && <PillBarButton prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'reaction']} onChange={this.onPushChange} label={pushStr} />}
|
|
||||||
<PillBarButton prefix='notifications' settings={settings} settingPath={['shows', 'reaction']} onChange={onChange} label={showStr} />
|
|
||||||
<PillBarButton prefix='notifications' settings={settings} settingPath={['sounds', 'reaction']} onChange={onChange} label={soundStr} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div role='group' aria-labelledby='notifications-mention'>
|
<div role='group' aria-labelledby='notifications-mention'>
|
||||||
<span id='notifications-mention' className='column-settings__section'><FormattedMessage id='notifications.column_settings.mention' defaultMessage='Mentions:' /></span>
|
<span id='notifications-mention' className='column-settings__section'><FormattedMessage id='notifications.column_settings.mention' defaultMessage='Mentions:' /></span>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { PureComponent } from 'react';
|
||||||
|
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import AddReactionIcon from '@/material-icons/400-24px/add_reaction.svg?react';
|
|
||||||
import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
||||||
import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react';
|
import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react';
|
||||||
import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react';
|
import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react';
|
||||||
|
@ -16,7 +15,6 @@ import { Icon } from 'flavours/glitch/components/icon';
|
||||||
const tooltips = defineMessages({
|
const tooltips = defineMessages({
|
||||||
mentions: { id: 'notifications.filter.mentions', defaultMessage: 'Mentions' },
|
mentions: { id: 'notifications.filter.mentions', defaultMessage: 'Mentions' },
|
||||||
favourites: { id: 'notifications.filter.favourites', defaultMessage: 'Favorites' },
|
favourites: { id: 'notifications.filter.favourites', defaultMessage: 'Favorites' },
|
||||||
reactions: { id: 'notifications.filter.reactions', defaultMessage: 'Reactions' },
|
|
||||||
boosts: { id: 'notifications.filter.boosts', defaultMessage: 'Boosts' },
|
boosts: { id: 'notifications.filter.boosts', defaultMessage: 'Boosts' },
|
||||||
polls: { id: 'notifications.filter.polls', defaultMessage: 'Poll results' },
|
polls: { id: 'notifications.filter.polls', defaultMessage: 'Poll results' },
|
||||||
follows: { id: 'notifications.filter.follows', defaultMessage: 'Follows' },
|
follows: { id: 'notifications.filter.follows', defaultMessage: 'Follows' },
|
||||||
|
@ -84,13 +82,6 @@ class FilterBar extends PureComponent {
|
||||||
>
|
>
|
||||||
<Icon id='star' icon={StarIcon} />
|
<Icon id='star' icon={StarIcon} />
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
className={selectedFilter === 'reaction' ? 'active' : ''}
|
|
||||||
onClick={this.onClick('reaction')}
|
|
||||||
title={intl.formatMessage(tooltips.reactions)}
|
|
||||||
>
|
|
||||||
<Icon id='add_reaction' icon={AddReactionIcon} />
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
className={selectedFilter === 'reblog' ? 'active' : ''}
|
className={selectedFilter === 'reblog' ? 'active' : ''}
|
||||||
onClick={this.onClick('reblog')}
|
onClick={this.onClick('reblog')}
|
||||||
|
|
|
@ -159,28 +159,6 @@ export default class Notification extends ImmutablePureComponent {
|
||||||
unread={this.props.unread}
|
unread={this.props.unread}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'reaction':
|
|
||||||
return (
|
|
||||||
<StatusContainer
|
|
||||||
containerId={notification.get('id')}
|
|
||||||
hidden={hidden}
|
|
||||||
id={notification.get('status')}
|
|
||||||
account={notification.get('account')}
|
|
||||||
prepend='reaction'
|
|
||||||
muted
|
|
||||||
notification={notification}
|
|
||||||
onMoveDown={onMoveDown}
|
|
||||||
onMoveUp={onMoveUp}
|
|
||||||
onMention={onMention}
|
|
||||||
getScrollPosition={getScrollPosition}
|
|
||||||
updateScrollBottom={updateScrollBottom}
|
|
||||||
cachedMediaWidth={this.props.cachedMediaWidth}
|
|
||||||
cacheMediaWidth={this.props.cacheMediaWidth}
|
|
||||||
onUnmount={this.props.onUnmount}
|
|
||||||
withDismiss
|
|
||||||
unread={this.props.unread}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'reblog':
|
case 'reblog':
|
||||||
return (
|
return (
|
||||||
<StatusContainer
|
<StatusContainer
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
|
||||||
import AddReactionIcon from '@/material-icons/400-24px/add_reaction.svg?react';
|
|
||||||
import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg?react';
|
import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg?react';
|
||||||
import BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react';
|
import BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react';
|
||||||
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
||||||
|
@ -28,8 +27,7 @@ import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
|
||||||
|
|
||||||
import { IconButton } from '../../../components/icon_button';
|
import { IconButton } from '../../../components/icon_button';
|
||||||
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
|
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
|
||||||
import { me, maxReactions } from '../../../initial_state';
|
import { me } from '../../../initial_state';
|
||||||
import EmojiPickerDropdown from '../../compose/containers/emoji_picker_dropdown_container';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
||||||
|
@ -44,7 +42,6 @@ const messages = defineMessages({
|
||||||
cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
|
cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
|
||||||
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
|
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
|
||||||
favourite: { id: 'status.favourite', defaultMessage: 'Favorite' },
|
favourite: { id: 'status.favourite', defaultMessage: 'Favorite' },
|
||||||
react: { id: 'status.react', defaultMessage: 'React' },
|
|
||||||
bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' },
|
bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' },
|
||||||
more: { id: 'status.more', defaultMessage: 'More' },
|
more: { id: 'status.more', defaultMessage: 'More' },
|
||||||
mute: { id: 'status.mute', defaultMessage: 'Mute @{name}' },
|
mute: { id: 'status.mute', defaultMessage: 'Mute @{name}' },
|
||||||
|
@ -74,7 +71,6 @@ class ActionBar extends PureComponent {
|
||||||
onReply: PropTypes.func.isRequired,
|
onReply: PropTypes.func.isRequired,
|
||||||
onReblog: PropTypes.func.isRequired,
|
onReblog: PropTypes.func.isRequired,
|
||||||
onFavourite: PropTypes.func.isRequired,
|
onFavourite: PropTypes.func.isRequired,
|
||||||
onReactionAdd: PropTypes.func.isRequired,
|
|
||||||
onBookmark: PropTypes.func.isRequired,
|
onBookmark: PropTypes.func.isRequired,
|
||||||
onDelete: PropTypes.func.isRequired,
|
onDelete: PropTypes.func.isRequired,
|
||||||
onEdit: PropTypes.func.isRequired,
|
onEdit: PropTypes.func.isRequired,
|
||||||
|
@ -103,10 +99,6 @@ class ActionBar extends PureComponent {
|
||||||
this.props.onFavourite(this.props.status, e);
|
this.props.onFavourite(this.props.status, e);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleEmojiPick = data => {
|
|
||||||
this.props.onReactionAdd(this.props.status.get('id'), data.native.replace(/:/g, ''), data.imageUrl);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleBookmarkClick = (e) => {
|
handleBookmarkClick = (e) => {
|
||||||
this.props.onBookmark(this.props.status, e);
|
this.props.onBookmark(this.props.status, e);
|
||||||
};
|
};
|
||||||
|
@ -170,8 +162,6 @@ class ActionBar extends PureComponent {
|
||||||
navigator.clipboard.writeText(url);
|
navigator.clipboard.writeText(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleNoOp = () => {}; // hack for reaction add button
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { status, intl } = this.props;
|
const { status, intl } = this.props;
|
||||||
const { signedIn, permissions } = this.context.identity;
|
const { signedIn, permissions } = this.context.identity;
|
||||||
|
@ -248,18 +238,6 @@ class ActionBar extends PureComponent {
|
||||||
replyIconComponent = ReplyAllIcon;
|
replyIconComponent = ReplyAllIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
const canReact = signedIn && status.get('reactions').filter(r => r.get('count') > 0 && r.get('me')).size < maxReactions;
|
|
||||||
const reactButton = (
|
|
||||||
<IconButton
|
|
||||||
className='add-reaction-icon'
|
|
||||||
onClick={this.handleNoOp} // EmojiPickerDropdown handles that
|
|
||||||
title={intl.formatMessage(messages.react)}
|
|
||||||
disabled={!canReact}
|
|
||||||
icon='add_reaction'
|
|
||||||
iconComponent={AddReactionIcon}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
|
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
|
||||||
|
|
||||||
let reblogTitle, reblogIconComponent;
|
let reblogTitle, reblogIconComponent;
|
||||||
|
@ -284,13 +262,6 @@ class ActionBar extends PureComponent {
|
||||||
<div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={reblogIconComponent} onClick={this.handleReblogClick} /></div>
|
<div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={reblogIconComponent} onClick={this.handleReblogClick} /></div>
|
||||||
<div className='detailed-status__button'><IconButton className='quote-right-icon' disabled={!publicStatus} title={intl.formatMessage(messages.quote)} icon='quote-right' iconComponent={QuoteIcon} onClick={this.handleQuoteClick} /></div>
|
<div className='detailed-status__button'><IconButton className='quote-right-icon' disabled={!publicStatus} title={intl.formatMessage(messages.quote)} icon='quote-right' iconComponent={QuoteIcon} onClick={this.handleQuoteClick} /></div>
|
||||||
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} /></div>
|
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} /></div>
|
||||||
<div className='detailed-status__button'>
|
|
||||||
{
|
|
||||||
signedIn
|
|
||||||
? <EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={reactButton} disabled={!canReact} />
|
|
||||||
: reactButton
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} /></div>
|
<div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} /></div>
|
||||||
|
|
||||||
<div className='detailed-status__action-bar-dropdown'>
|
<div className='detailed-status__action-bar-dropdown'>
|
||||||
|
|
|
@ -25,7 +25,6 @@ import { Avatar } from '../../../components/avatar';
|
||||||
import { DisplayName } from '../../../components/display_name';
|
import { DisplayName } from '../../../components/display_name';
|
||||||
import MediaGallery from '../../../components/media_gallery';
|
import MediaGallery from '../../../components/media_gallery';
|
||||||
import StatusContent from '../../../components/status_content';
|
import StatusContent from '../../../components/status_content';
|
||||||
import StatusReactions from '../../../components/status_reactions';
|
|
||||||
import Audio from '../../audio';
|
import Audio from '../../audio';
|
||||||
import scheduleIdleTask from '../../ui/util/schedule_idle_task';
|
import scheduleIdleTask from '../../ui/util/schedule_idle_task';
|
||||||
import Video from '../../video';
|
import Video from '../../video';
|
||||||
|
@ -34,10 +33,6 @@ import Card from './card';
|
||||||
|
|
||||||
class DetailedStatus extends ImmutablePureComponent {
|
class DetailedStatus extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
status: ImmutablePropTypes.map,
|
status: ImmutablePropTypes.map,
|
||||||
settings: ImmutablePropTypes.map.isRequired,
|
settings: ImmutablePropTypes.map.isRequired,
|
||||||
|
@ -56,8 +51,6 @@ class DetailedStatus extends ImmutablePureComponent {
|
||||||
available: PropTypes.bool,
|
available: PropTypes.bool,
|
||||||
}),
|
}),
|
||||||
onToggleMediaVisibility: PropTypes.func,
|
onToggleMediaVisibility: PropTypes.func,
|
||||||
onReactionAdd: PropTypes.func.isRequired,
|
|
||||||
onReactionRemove: PropTypes.func.isRequired,
|
|
||||||
...WithRouterPropTypes,
|
...WithRouterPropTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -336,14 +329,6 @@ class DetailedStatus extends ImmutablePureComponent {
|
||||||
{...statusContentProps}
|
{...statusContentProps}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<StatusReactions
|
|
||||||
statusId={status.get('id')}
|
|
||||||
reactions={status.get('reactions')}
|
|
||||||
addReaction={this.props.onReactionAdd}
|
|
||||||
removeReaction={this.props.onReactionRemove}
|
|
||||||
canReact={this.context.identity.signedIn}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className='detailed-status__meta'>
|
<div className='detailed-status__meta'>
|
||||||
<a className='detailed-status__datetime' href={status.get('url')} target='_blank' rel='noopener noreferrer'>
|
<a className='detailed-status__datetime' href={status.get('url')} target='_blank' rel='noopener noreferrer'>
|
||||||
<FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
|
<FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
|
||||||
|
|
|
@ -41,8 +41,6 @@ import {
|
||||||
unreblog,
|
unreblog,
|
||||||
pin,
|
pin,
|
||||||
unpin,
|
unpin,
|
||||||
addReaction,
|
|
||||||
removeReaction,
|
|
||||||
} from '../../actions/interactions';
|
} from '../../actions/interactions';
|
||||||
import { changeLocalSetting } from '../../actions/local_settings';
|
import { changeLocalSetting } from '../../actions/local_settings';
|
||||||
import { openModal } from '../../actions/modal';
|
import { openModal } from '../../actions/modal';
|
||||||
|
@ -311,19 +309,6 @@ class Status extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleReactionAdd = (statusId, name, url) => {
|
|
||||||
const { dispatch } = this.props;
|
|
||||||
const { signedIn } = this.context.identity;
|
|
||||||
|
|
||||||
if (signedIn) {
|
|
||||||
dispatch(addReaction(statusId, name, url));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleReactionRemove = (statusId, name) => {
|
|
||||||
this.props.dispatch(removeReaction(statusId, name));
|
|
||||||
};
|
|
||||||
|
|
||||||
handlePin = (status) => {
|
handlePin = (status) => {
|
||||||
if (status.get('pinned')) {
|
if (status.get('pinned')) {
|
||||||
this.props.dispatch(unpin(status));
|
this.props.dispatch(unpin(status));
|
||||||
|
@ -779,8 +764,6 @@ class Status extends ImmutablePureComponent {
|
||||||
settings={settings}
|
settings={settings}
|
||||||
onOpenVideo={this.handleOpenVideo}
|
onOpenVideo={this.handleOpenVideo}
|
||||||
onOpenMedia={this.handleOpenMedia}
|
onOpenMedia={this.handleOpenMedia}
|
||||||
onReactionAdd={this.handleReactionAdd}
|
|
||||||
onReactionRemove={this.handleReactionRemove}
|
|
||||||
expanded={isExpanded}
|
expanded={isExpanded}
|
||||||
onToggleHidden={this.handleToggleHidden}
|
onToggleHidden={this.handleToggleHidden}
|
||||||
onTranslate={this.handleTranslate}
|
onTranslate={this.handleTranslate}
|
||||||
|
@ -795,7 +778,6 @@ class Status extends ImmutablePureComponent {
|
||||||
status={status}
|
status={status}
|
||||||
onReply={this.handleReplyClick}
|
onReply={this.handleReplyClick}
|
||||||
onFavourite={this.handleFavouriteClick}
|
onFavourite={this.handleFavouriteClick}
|
||||||
onReactionAdd={this.handleReactionAdd}
|
|
||||||
onReblog={this.handleReblogClick}
|
onReblog={this.handleReblogClick}
|
||||||
onBookmark={this.handleBookmarkClick}
|
onBookmark={this.handleBookmarkClick}
|
||||||
onQuote={this.handleQuoteClick}
|
onQuote={this.handleQuoteClick}
|
||||||
|
|
|
@ -9,6 +9,10 @@ import { connect } from 'react-redux';
|
||||||
import Atrament from 'atrament'; // the doodling library
|
import Atrament from 'atrament'; // the doodling library
|
||||||
import { debounce, mapValues } from 'lodash';
|
import { debounce, mapValues } from 'lodash';
|
||||||
|
|
||||||
|
import ColorsIcon from '@/material-icons/400-24px/colors.svg?react';
|
||||||
|
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
|
||||||
|
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
|
||||||
|
import UndoIcon from '@/material-icons/400-24px/undo.svg?react';
|
||||||
import { doodleSet, uploadCompose } from 'flavours/glitch/actions/compose';
|
import { doodleSet, uploadCompose } from 'flavours/glitch/actions/compose';
|
||||||
import { Button } from 'flavours/glitch/components/button';
|
import { Button } from 'flavours/glitch/components/button';
|
||||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
|
@ -584,10 +588,10 @@ class DoodleModal extends ImmutablePureComponent {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='doodle-toolbar'>
|
<div className='doodle-toolbar'>
|
||||||
<IconButton icon='pencil' title='Draw' label='Draw' onClick={this.setModeDraw} size={18} active={this.mode === 'draw'} inverted />
|
<IconButton icon='pencil' iconComponent={EditIcon} title='Draw' label='Draw' onClick={this.setModeDraw} size={18} active={this.mode === 'draw'} inverted />
|
||||||
<IconButton icon='bath' title='Fill' label='Fill' onClick={this.setModeFill} size={18} active={this.mode === 'fill'} inverted />
|
<IconButton icon='bath' iconComponent={ColorsIcon} title='Fill' label='Fill' onClick={this.setModeFill} size={18} active={this.mode === 'fill'} inverted />
|
||||||
<IconButton icon='undo' title='Undo' label='Undo' onClick={this.undo} size={18} inverted />
|
<IconButton icon='undo' iconComponent={UndoIcon} title='Undo' label='Undo' onClick={this.undo} size={18} inverted />
|
||||||
<IconButton icon='trash' title='Clear' label='Clear' onClick={this.handleClearBtn} size={18} inverted />
|
<IconButton icon='trash' iconComponent={DeleteIcon} title='Clear' label='Clear' onClick={this.handleClearBtn} size={18} inverted />
|
||||||
</div>
|
</div>
|
||||||
<div className='doodle-palette'>
|
<div className='doodle-palette'>
|
||||||
{
|
{
|
||||||
|
|
|
@ -602,18 +602,7 @@ class UI extends PureComponent {
|
||||||
const { draggingOver } = this.state;
|
const { draggingOver } = this.state;
|
||||||
const { children, isWide, location, dropdownMenuIsOpen, layout, moved } = this.props;
|
const { children, isWide, location, dropdownMenuIsOpen, layout, moved } = this.props;
|
||||||
|
|
||||||
const columnsClass = layout => {
|
const className = classNames('ui', {
|
||||||
switch (layout) {
|
|
||||||
case 'single':
|
|
||||||
return 'single-column';
|
|
||||||
case 'multiple':
|
|
||||||
return 'multi-columns';
|
|
||||||
default:
|
|
||||||
return 'auto-columns';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const className = classNames('ui', columnsClass(layout), {
|
|
||||||
'wide': isWide,
|
'wide': isWide,
|
||||||
'system-font': this.props.systemFontUi,
|
'system-font': this.props.systemFontUi,
|
||||||
'hicolor-privacy-icons': this.props.hicolorPrivacyIcons,
|
'hicolor-privacy-icons': this.props.hicolorPrivacyIcons,
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
* @property {boolean} limited_federation_mode
|
* @property {boolean} limited_federation_mode
|
||||||
* @property {string} locale
|
* @property {string} locale
|
||||||
* @property {string | null} mascot
|
* @property {string | null} mascot
|
||||||
* @property {number} max_reactions
|
|
||||||
* @property {string=} me
|
* @property {string=} me
|
||||||
* @property {string=} moved_to_account_id
|
* @property {string=} moved_to_account_id
|
||||||
* @property {string=} owner
|
* @property {string=} owner
|
||||||
|
@ -45,7 +44,6 @@
|
||||||
* @property {boolean} use_blurhash
|
* @property {boolean} use_blurhash
|
||||||
* @property {boolean=} use_pending_items
|
* @property {boolean=} use_pending_items
|
||||||
* @property {string} version
|
* @property {string} version
|
||||||
* @property {number} visible_reactions
|
|
||||||
* @property {string} sso_redirect
|
* @property {string} sso_redirect
|
||||||
* @property {boolean} translation_enabled
|
* @property {boolean} translation_enabled
|
||||||
* @property {string} status_page_url
|
* @property {string} status_page_url
|
||||||
|
@ -69,8 +67,8 @@ export const hasMultiColumnPath = initialPath === '/'
|
||||||
* @property {InitialStateMeta} meta
|
* @property {InitialStateMeta} meta
|
||||||
* @property {object} local_settings
|
* @property {object} local_settings
|
||||||
* @property {number} max_toot_chars
|
* @property {number} max_toot_chars
|
||||||
|
* @property {number} max_feed_hashtags
|
||||||
* @property {number} poll_limits
|
* @property {number} poll_limits
|
||||||
* @property {number} max_reactions
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const element = document.getElementById('initial-state');
|
const element = document.getElementById('initial-state');
|
||||||
|
@ -107,7 +105,6 @@ export const expandSpoilers = getMeta('expand_spoilers');
|
||||||
export const forceSingleColumn = !getMeta('advanced_layout');
|
export const forceSingleColumn = !getMeta('advanced_layout');
|
||||||
export const limitedFederationMode = getMeta('limited_federation_mode');
|
export const limitedFederationMode = getMeta('limited_federation_mode');
|
||||||
export const mascot = getMeta('mascot');
|
export const mascot = getMeta('mascot');
|
||||||
export const maxReactions = (initialState && initialState.max_reactions) || 1;
|
|
||||||
export const me = getMeta('me');
|
export const me = getMeta('me');
|
||||||
export const movedToAccountId = getMeta('moved_to_account_id');
|
export const movedToAccountId = getMeta('moved_to_account_id');
|
||||||
export const owner = getMeta('owner');
|
export const owner = getMeta('owner');
|
||||||
|
@ -127,7 +124,6 @@ export const unfollowModal = getMeta('unfollow_modal');
|
||||||
export const useBlurhash = getMeta('use_blurhash');
|
export const useBlurhash = getMeta('use_blurhash');
|
||||||
export const usePendingItems = getMeta('use_pending_items');
|
export const usePendingItems = getMeta('use_pending_items');
|
||||||
export const version = getMeta('version');
|
export const version = getMeta('version');
|
||||||
export const visibleReactions = getMeta('visible_reactions');
|
|
||||||
export const languages = initialState?.languages;
|
export const languages = initialState?.languages;
|
||||||
export const criticalUpdatesPending = initialState?.critical_updates_pending;
|
export const criticalUpdatesPending = initialState?.critical_updates_pending;
|
||||||
export const statusPageUrl = getMeta('status_page_url');
|
export const statusPageUrl = getMeta('status_page_url');
|
||||||
|
@ -135,6 +131,7 @@ export const sso_redirect = getMeta('sso_redirect');
|
||||||
|
|
||||||
// Glitch-soc-specific settings
|
// Glitch-soc-specific settings
|
||||||
export const maxChars = (initialState && initialState.max_toot_chars) || 500;
|
export const maxChars = (initialState && initialState.max_toot_chars) || 500;
|
||||||
|
export const maxFeedHashtags = (initialState && initialState.max_feed_hashtags) || 4;
|
||||||
export const favouriteModal = getMeta('favourite_modal');
|
export const favouriteModal = getMeta('favourite_modal');
|
||||||
export const pollLimits = (initialState && initialState.poll_limits);
|
export const pollLimits = (initialState && initialState.poll_limits);
|
||||||
export const defaultContentType = getMeta('default_content_type');
|
export const defaultContentType = getMeta('default_content_type');
|
||||||
|
|
|
@ -60,14 +60,11 @@
|
||||||
"navigation_bar.keyboard_shortcuts": "Keyboard shortcuts",
|
"navigation_bar.keyboard_shortcuts": "Keyboard shortcuts",
|
||||||
"navigation_bar.misc": "Misc",
|
"navigation_bar.misc": "Misc",
|
||||||
"notification.markForDeletion": "Mark for deletion",
|
"notification.markForDeletion": "Mark for deletion",
|
||||||
"notification.reaction": "{name} reacted to your post",
|
|
||||||
"notification_purge.btn_all": "Select\nall",
|
"notification_purge.btn_all": "Select\nall",
|
||||||
"notification_purge.btn_apply": "Clear\nselected",
|
"notification_purge.btn_apply": "Clear\nselected",
|
||||||
"notification_purge.btn_invert": "Invert\nselection",
|
"notification_purge.btn_invert": "Invert\nselection",
|
||||||
"notification_purge.btn_none": "Select\nnone",
|
"notification_purge.btn_none": "Select\nnone",
|
||||||
"notification_purge.start": "Enter notification cleaning mode",
|
"notification_purge.start": "Enter notification cleaning mode",
|
||||||
"notifications.column_settings.reaction": "Reactions:",
|
|
||||||
"notifications.filter.reactions": "Reactions",
|
|
||||||
"notifications.marked_clear": "Clear selected notifications",
|
"notifications.marked_clear": "Clear selected notifications",
|
||||||
"notifications.marked_clear_confirmation": "Are you sure you want to permanently clear all selected notifications?",
|
"notifications.marked_clear_confirmation": "Are you sure you want to permanently clear all selected notifications?",
|
||||||
"settings.always_show_spoilers_field": "Always enable the Content Warning field",
|
"settings.always_show_spoilers_field": "Always enable the Content Warning field",
|
||||||
|
@ -157,7 +154,6 @@
|
||||||
"status.in_reply_to": "This toot is a reply",
|
"status.in_reply_to": "This toot is a reply",
|
||||||
"status.is_poll": "This toot is a poll",
|
"status.is_poll": "This toot is a poll",
|
||||||
"status.local_only": "Only visible from your instance",
|
"status.local_only": "Only visible from your instance",
|
||||||
"status.react": "React",
|
|
||||||
"status.sensitive_toggle": "Click to view",
|
"status.sensitive_toggle": "Click to view",
|
||||||
"status.uncollapse": "Uncollapse",
|
"status.uncollapse": "Uncollapse",
|
||||||
"suggestions.dismiss": "Dismiss suggestion"
|
"suggestions.dismiss": "Dismiss suggestion"
|
||||||
|
|
|
@ -1,4 +1,51 @@
|
||||||
{
|
{
|
||||||
|
"about.fork_disclaimer": "Glitch-soc adalah perangkat lunak sumber terbuka yang merupakan fork dari Mastodon.",
|
||||||
|
"account.disclaimer_full": "Informasi di bawah ini mungkin tidak mencerminkan profil pengguna secara lengkap.",
|
||||||
|
"account.follows": "Mengikuti",
|
||||||
|
"account.joined": "Bergabung {date}",
|
||||||
|
"account.suspended_disclaimer_full": "Pengguna ini telah ditangguhkan oleh moderator.",
|
||||||
|
"account.view_full_profile": "Tampilkan profil lengkap",
|
||||||
|
"advanced_options.icon_title": "Opsi lanjutan",
|
||||||
|
"advanced_options.local-only.long": "Jangan mengunggah ke instance lain",
|
||||||
|
"advanced_options.local-only.short": "Hanya lokal",
|
||||||
|
"advanced_options.local-only.tooltip": "Postingan ini hanya untuk lokal",
|
||||||
|
"advanced_options.threaded_mode.long": "Secara otomatis membuka balasan pada postingan",
|
||||||
|
"advanced_options.threaded_mode.short": "Mode Utasan",
|
||||||
|
"advanced_options.threaded_mode.tooltip": "Mode utasan dinyalakan",
|
||||||
|
"boost_modal.missing_description": "Toot ini berisi beberapa media tanpa deskripsi",
|
||||||
|
"column.favourited_by": "Disukai oleh",
|
||||||
|
"column.heading": "Lainnya",
|
||||||
|
"column.reblogged_by": "Dibagikan oleh",
|
||||||
|
"column.subheading": "Opsi lain-lain",
|
||||||
|
"column_header.profile": "Profil",
|
||||||
|
"column_subheading.lists": "Daftar",
|
||||||
|
"column_subheading.navigation": "Penelusuran",
|
||||||
|
"community.column_settings.allow_local_only": "Tampilkan toot lokal saja",
|
||||||
|
"compose.attach": "Lampirkan...",
|
||||||
|
"compose.attach.doodle": "Gambar sesuatu",
|
||||||
|
"compose.attach.upload": "Unggah file",
|
||||||
|
"compose.content-type.html": "HTML",
|
||||||
|
"compose.content-type.markdown": "Bahasa Markdown",
|
||||||
|
"compose.content-type.plain": "Teks biasa",
|
||||||
|
"compose_form.poll.multiple_choices": "Izinkan beberapa pilihan",
|
||||||
|
"compose_form.poll.single_choice": "Izinkan hanya satu pilihan",
|
||||||
|
"compose_form.spoiler": "Sembunyikan teks di balik peringatan",
|
||||||
|
"confirmation_modal.do_not_ask_again": "Jangan minta konfirmasi lagi",
|
||||||
|
"confirmations.deprecated_settings.confirm": "Gunakan preferensi Mastodon",
|
||||||
|
"confirmations.deprecated_settings.message": "Beberapa {app_settings} khusus perangkat Glitch-soc yang Anda gunakan telah digantikan oleh {preferences} Mastodon dan akan diganti:",
|
||||||
|
"confirmations.missing_media_description.confirm": "Tetap kirim",
|
||||||
|
"confirmations.missing_media_description.edit": "Sunting media",
|
||||||
|
"confirmations.missing_media_description.message": "Setidaknya satu lampiran media tidak memiliki deskripsi. Pertimbangkan untuk mendeskripsikan semua lampiran media untuk pengguna tunanetra sebelum mengirim toot Anda.",
|
||||||
|
"confirmations.unfilter.author": "Penulis",
|
||||||
|
"confirmations.unfilter.confirm": "Tampilkan",
|
||||||
|
"confirmations.unfilter.edit_filter": "Ubah saringan",
|
||||||
|
"content-type.change": "Jenis konten",
|
||||||
|
"direct.group_by_conversations": "Grupkan berdasarkan percakapan",
|
||||||
|
"endorsed_accounts_editor.endorsed_accounts": "Akun pilihan",
|
||||||
|
"favourite_modal.combo": "Anda dapat menekan {combo} untuk melewati ini lain kali",
|
||||||
|
"firehose.column_settings.allow_local_only": "Tampilkan postingan khusus lokal di \"Semua\"",
|
||||||
|
"home.column_settings.advanced": "Lanjutan",
|
||||||
|
"home.column_settings.filter_regex": "Saring dengan ekspresi reguler",
|
||||||
"settings.content_warnings": "Content warnings",
|
"settings.content_warnings": "Content warnings",
|
||||||
"settings.preferences": "Preferences"
|
"settings.preferences": "Preferences"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,52 @@
|
||||||
{
|
{
|
||||||
|
"account.follows": "Följer",
|
||||||
|
"account.joined": "Gick med {date}",
|
||||||
|
"account.suspended_disclaimer_full": "Denna användare har stängts av av en moderator.",
|
||||||
|
"account.view_full_profile": "Visa full profil",
|
||||||
|
"advanced_options.icon_title": "Avancerade inställningar",
|
||||||
|
"advanced_options.local-only.long": "Lägg inte ut på andra instanser",
|
||||||
|
"advanced_options.local-only.short": "Endast lokalt",
|
||||||
|
"advanced_options.local-only.tooltip": "Detta inlägg är endast tillgängligt lokalt",
|
||||||
|
"advanced_options.threaded_mode.long": "Öppnar automatiskt ett svar vid publicering",
|
||||||
|
"advanced_options.threaded_mode.short": "Tråd-läge",
|
||||||
|
"advanced_options.threaded_mode.tooltip": "Tråd-läge på",
|
||||||
|
"boost_modal.missing_description": "Denna toot innehåller viss media utan beskrivning",
|
||||||
|
"column.favourited_by": "Favoritmarkerad av",
|
||||||
|
"column.heading": "Övrigt",
|
||||||
|
"column.reblogged_by": "Boostad av",
|
||||||
|
"column.subheading": "Övriga val",
|
||||||
|
"column_header.profile": "Profil",
|
||||||
|
"column_subheading.lists": "Listor",
|
||||||
|
"column_subheading.navigation": "Navigering",
|
||||||
|
"community.column_settings.allow_local_only": "Visa endast lokala toots",
|
||||||
|
"compose.attach": "Bifoga...",
|
||||||
|
"compose.attach.doodle": "Rita något",
|
||||||
|
"compose.attach.upload": "Ladda upp en fil",
|
||||||
|
"compose.content-type.html": "HTML",
|
||||||
|
"compose.content-type.markdown": "Markdown",
|
||||||
|
"compose.content-type.plain": "Klartext",
|
||||||
|
"compose_form.poll.multiple_choices": "Tillåt flera val",
|
||||||
|
"compose_form.poll.single_choice": "Tillåt ett val",
|
||||||
|
"compose_form.spoiler": "Göm text bakom varning",
|
||||||
|
"confirmation_modal.do_not_ask_again": "Fråga mig inte igen",
|
||||||
|
"confirmations.deprecated_settings.confirm": "Använd Mastodon-preferenser",
|
||||||
|
"confirmations.deprecated_settings.message": "Några av de glitch-soc-enhetsspecifika {app_settings} som du använder har ersatts av Mastodon-{preferences} och kommer att åsidosättas:",
|
||||||
|
"confirmations.missing_media_description.confirm": "Lägg ut ändå",
|
||||||
|
"confirmations.missing_media_description.edit": "Redigera media",
|
||||||
|
"confirmations.missing_media_description.message": "Minst en mediebilaga saknar beskrivning. Överväg att beskriva all media för synskadade innan du skickar din toot.",
|
||||||
|
"confirmations.unfilter.author": "Användare",
|
||||||
|
"confirmations.unfilter.confirm": "Visa",
|
||||||
|
"confirmations.unfilter.edit_filter": "Redigera filter",
|
||||||
|
"confirmations.unfilter.filters": "Matchande {count, plural, one {filter} other {filters}}",
|
||||||
|
"content-type.change": "Innehållstyp",
|
||||||
|
"direct.group_by_conversations": "Sortera efter konversation",
|
||||||
|
"endorsed_accounts_editor.endorsed_accounts": "Utvalda konton",
|
||||||
|
"favourite_modal.combo": "Du kan trycka på {combo} för att skippa detta nästa gång",
|
||||||
|
"firehose.column_settings.allow_local_only": "Visa endast lokala inlägg i \"Alla\"",
|
||||||
|
"home.column_settings.advanced": "Avancerat",
|
||||||
|
"home.column_settings.filter_regex": "Filtrera bort med reguljära uttryck",
|
||||||
|
"home.column_settings.show_direct": "Visa privata omnämningar",
|
||||||
|
"home.settings": "Kolumninställningar",
|
||||||
"settings.content_warnings": "Content warnings",
|
"settings.content_warnings": "Content warnings",
|
||||||
"settings.preferences": "Preferences"
|
"settings.preferences": "Preferences"
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,7 @@ const initialState = ImmutableMap({
|
||||||
export default function meta(state = initialState, action) {
|
export default function meta(state = initialState, action) {
|
||||||
switch(action.type) {
|
switch(action.type) {
|
||||||
case STORE_HYDRATE:
|
case STORE_HYDRATE:
|
||||||
return state.merge(action.state.get('meta'))
|
return state.merge(action.state.get('meta')).set('permissions', action.state.getIn(['role', 'permissions']));
|
||||||
.set('permissions', action.state.getIn(['role', 'permissions']))
|
|
||||||
.set('layout', layoutFromWindow(action.state.getIn(['local_settings', 'layout'])));
|
|
||||||
case changeLayout.type:
|
case changeLayout.type:
|
||||||
return state.set('layout', action.payload.layout);
|
return state.set('layout', action.payload.layout);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -38,7 +38,6 @@ const initialState = ImmutableMap({
|
||||||
follow: false,
|
follow: false,
|
||||||
follow_request: false,
|
follow_request: false,
|
||||||
favourite: false,
|
favourite: false,
|
||||||
reaction: false,
|
|
||||||
reblog: false,
|
reblog: false,
|
||||||
mention: false,
|
mention: false,
|
||||||
poll: false,
|
poll: false,
|
||||||
|
@ -61,7 +60,6 @@ const initialState = ImmutableMap({
|
||||||
follow: true,
|
follow: true,
|
||||||
follow_request: false,
|
follow_request: false,
|
||||||
favourite: true,
|
favourite: true,
|
||||||
reaction: true,
|
|
||||||
reblog: true,
|
reblog: true,
|
||||||
mention: true,
|
mention: true,
|
||||||
poll: true,
|
poll: true,
|
||||||
|
@ -75,7 +73,6 @@ const initialState = ImmutableMap({
|
||||||
follow: true,
|
follow: true,
|
||||||
follow_request: false,
|
follow_request: false,
|
||||||
favourite: true,
|
favourite: true,
|
||||||
reaction: true,
|
|
||||||
reblog: true,
|
reblog: true,
|
||||||
mention: true,
|
mention: true,
|
||||||
poll: true,
|
poll: true,
|
||||||
|
|
|
@ -15,11 +15,6 @@ import {
|
||||||
BOOKMARK_FAIL,
|
BOOKMARK_FAIL,
|
||||||
UNBOOKMARK_REQUEST,
|
UNBOOKMARK_REQUEST,
|
||||||
UNBOOKMARK_FAIL,
|
UNBOOKMARK_FAIL,
|
||||||
REACTION_UPDATE,
|
|
||||||
REACTION_ADD_FAIL,
|
|
||||||
REACTION_REMOVE_FAIL,
|
|
||||||
REACTION_ADD_REQUEST,
|
|
||||||
REACTION_REMOVE_REQUEST,
|
|
||||||
} from '../actions/interactions';
|
} from '../actions/interactions';
|
||||||
import {
|
import {
|
||||||
STATUS_MUTE_SUCCESS,
|
STATUS_MUTE_SUCCESS,
|
||||||
|
@ -47,43 +42,6 @@ const deleteStatus = (state, id, references) => {
|
||||||
return state.delete(id);
|
return state.delete(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateReaction = (state, id, name, updater) => state.update(
|
|
||||||
id,
|
|
||||||
status => status.update(
|
|
||||||
'reactions',
|
|
||||||
reactions => {
|
|
||||||
const index = reactions.findIndex(reaction => reaction.get('name') === name);
|
|
||||||
if (index > -1) {
|
|
||||||
return reactions.update(index, reaction => updater(reaction));
|
|
||||||
} else {
|
|
||||||
return reactions.push(updater(fromJS({ name, count: 0 })));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateReactionCount = (state, reaction) => updateReaction(state, reaction.status_id, reaction.name, x => x.set('count', reaction.count));
|
|
||||||
|
|
||||||
// The url parameter is only used when adding a new custom emoji reaction
|
|
||||||
// (one that wasn't in the reactions list before) because we don't have its
|
|
||||||
// URL yet. In all other cases, it's undefined.
|
|
||||||
const addReaction = (state, id, name, url) => updateReaction(
|
|
||||||
state,
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
x => x.set('me', true)
|
|
||||||
.update('count', n => n + 1)
|
|
||||||
.update('url', old => old ? old : url)
|
|
||||||
.update('static_url', old => old ? old : url),
|
|
||||||
);
|
|
||||||
|
|
||||||
const removeReaction = (state, id, name) => updateReaction(
|
|
||||||
state,
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
x => x.set('me', false).update('count', n => n - 1),
|
|
||||||
);
|
|
||||||
|
|
||||||
const statusTranslateSuccess = (state, id, translation) => {
|
const statusTranslateSuccess = (state, id, translation) => {
|
||||||
return state.withMutations(map => {
|
return state.withMutations(map => {
|
||||||
map.setIn([id, 'translation'], fromJS(normalizeStatusTranslation(translation, map.get(id))));
|
map.setIn([id, 'translation'], fromJS(normalizeStatusTranslation(translation, map.get(id))));
|
||||||
|
@ -137,14 +95,6 @@ export default function statuses(state = initialState, action) {
|
||||||
return state.setIn([action.status.get('id'), 'reblogged'], true);
|
return state.setIn([action.status.get('id'), 'reblogged'], true);
|
||||||
case REBLOG_FAIL:
|
case REBLOG_FAIL:
|
||||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], false);
|
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], false);
|
||||||
case REACTION_UPDATE:
|
|
||||||
return updateReactionCount(state, action.reaction);
|
|
||||||
case REACTION_ADD_REQUEST:
|
|
||||||
case REACTION_REMOVE_FAIL:
|
|
||||||
return addReaction(state, action.id, action.name, action.url);
|
|
||||||
case REACTION_REMOVE_REQUEST:
|
|
||||||
case REACTION_ADD_FAIL:
|
|
||||||
return removeReaction(state, action.id, action.name);
|
|
||||||
case UNREBLOG_REQUEST:
|
case UNREBLOG_REQUEST:
|
||||||
return state.setIn([action.status.get('id'), 'reblogged'], false);
|
return state.setIn([action.status.get('id'), 'reblogged'], false);
|
||||||
case UNREBLOG_FAIL:
|
case UNREBLOG_FAIL:
|
||||||
|
|
|
@ -10,37 +10,6 @@
|
||||||
background-size: $size $size;
|
background-size: $size $size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin single-column($media, $parent: '&') {
|
|
||||||
.auto-columns #{$parent} {
|
|
||||||
@media #{$media} {
|
|
||||||
@content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.single-column #{$parent} {
|
|
||||||
@content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin limited-single-column($media, $parent: '&') {
|
|
||||||
.auto-columns #{$parent},
|
|
||||||
.single-column #{$parent} {
|
|
||||||
@media #{$media} {
|
|
||||||
@content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin multi-columns($media, $parent: '&') {
|
|
||||||
.auto-columns #{$parent} {
|
|
||||||
@media #{$media} {
|
|
||||||
@content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.multi-columns #{$parent} {
|
|
||||||
@content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin fullwidth-gallery {
|
@mixin fullwidth-gallery {
|
||||||
&.full-width {
|
&.full-width {
|
||||||
margin-left: -14px;
|
margin-left: -14px;
|
||||||
|
|
9969
app/javascript/flavours/glitch/styles/components.scss
Normal file
|
@ -1,298 +0,0 @@
|
||||||
.image {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&__preview {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.loaded &__preview {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
border: 0;
|
|
||||||
background: transparent;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.loaded img {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-footer {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
padding: 10px;
|
|
||||||
padding-top: 20px;
|
|
||||||
z-index: 1;
|
|
||||||
font-size: 13px;
|
|
||||||
|
|
||||||
p {
|
|
||||||
color: $dark-text-color;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
.version {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: $dark-text-color;
|
|
||||||
text-decoration: underline;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.about {
|
|
||||||
padding: 20px;
|
|
||||||
|
|
||||||
@media screen and (min-width: $no-gap-breakpoint) {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__footer {
|
|
||||||
color: $dark-text-color;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 15px;
|
|
||||||
line-height: 22px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__header {
|
|
||||||
margin-bottom: 30px;
|
|
||||||
|
|
||||||
&__hero {
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
aspect-ratio: 1.9;
|
|
||||||
background: lighten($ui-base-color, 4%);
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,
|
|
||||||
p {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 1.5;
|
|
||||||
font-weight: 700;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 24px;
|
|
||||||
font-weight: 400;
|
|
||||||
color: $darker-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__meta {
|
|
||||||
background: lighten($ui-base-color, 4%);
|
|
||||||
border-radius: 4px;
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
font-size: 15px;
|
|
||||||
|
|
||||||
&__column {
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 50%;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__divider {
|
|
||||||
width: 0;
|
|
||||||
border: 0;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: lighten($ui-base-color, 8%);
|
|
||||||
border-left-width: 1px;
|
|
||||||
min-height: calc(100% - 60px);
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
font-size: 15px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: $darker-text-color;
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (width <= 600px) {
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__column {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__divider {
|
|
||||||
min-height: 0;
|
|
||||||
width: 100%;
|
|
||||||
border-left-width: 0;
|
|
||||||
border-top-width: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.layout-multiple-columns & {
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__column {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__divider {
|
|
||||||
min-height: 0;
|
|
||||||
width: 100%;
|
|
||||||
border-left-width: 0;
|
|
||||||
border-top-width: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__mail {
|
|
||||||
color: $primary-text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
font-weight: 500;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-footer {
|
|
||||||
padding: 0;
|
|
||||||
margin-top: 60px;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 15px;
|
|
||||||
line-height: 22px;
|
|
||||||
|
|
||||||
@media screen and (min-width: $no-gap-breakpoint) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account {
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__avatar-wrapper {
|
|
||||||
margin-inline-start: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__relationship {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__section {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
font-size: 17px;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 22px;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: lighten($ui-base-color, 4%);
|
|
||||||
color: $highlight-text-color;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active &__title {
|
|
||||||
border-radius: 4px 4px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__body {
|
|
||||||
border: 1px solid lighten($ui-base-color, 4%);
|
|
||||||
border-top: 0;
|
|
||||||
padding: 20px;
|
|
||||||
font-size: 15px;
|
|
||||||
line-height: 22px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__domain-blocks {
|
|
||||||
margin-top: 30px;
|
|
||||||
background: darken($ui-base-color, 4%);
|
|
||||||
border: 1px solid lighten($ui-base-color, 4%);
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&__domain {
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 4%);
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 15px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
|
|
||||||
&:nth-child(2n) {
|
|
||||||
background: darken($ui-base-color, 2%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__header {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h6 {
|
|
||||||
color: $secondary-text-color;
|
|
||||||
font-size: inherit;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,845 +0,0 @@
|
||||||
.account {
|
|
||||||
padding: 10px;
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
.account__display-name {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
overflow: hidden;
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
.display-name {
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.display-name strong {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--minimal {
|
|
||||||
.account__display-name {
|
|
||||||
.display-name {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.display-name strong {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__note {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 400;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-line-clamp: 1;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
margin-top: 10px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
|
|
||||||
&--missing {
|
|
||||||
color: $dark-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__wrapper {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__avatar-wrapper {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__avatar {
|
|
||||||
@include avatar-radius;
|
|
||||||
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
img {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-inline {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-inline-end: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-composite {
|
|
||||||
@include avatar-radius;
|
|
||||||
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
& > div {
|
|
||||||
@include avatar-radius;
|
|
||||||
|
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__avatar {
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__label {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
inset-inline-start: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
color: $primary-text-color;
|
|
||||||
text-shadow: 1px 1px 2px $base-shadow-color;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__avatar-overlay {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&-overlay {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
inset-inline-end: 0;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__relationship {
|
|
||||||
white-space: nowrap;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__header__wrapper {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
background: lighten($ui-base-color, 4%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__disclaimer {
|
|
||||||
display: flex;
|
|
||||||
padding: 10px;
|
|
||||||
gap: 5px;
|
|
||||||
color: $dark-text-color;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 500;
|
|
||||||
|
|
||||||
@each $lang in $cjk-langs {
|
|
||||||
&:lang(#{$lang}) {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: 500;
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: underline;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__action-bar {
|
|
||||||
border-top: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
line-height: 36px;
|
|
||||||
overflow: hidden;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__action-bar-links {
|
|
||||||
display: flex;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
line-height: 18px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__action-bar__tab {
|
|
||||||
text-decoration: none;
|
|
||||||
overflow: hidden;
|
|
||||||
flex: 0 1 100%;
|
|
||||||
border-inline-start: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
padding: 10px 0;
|
|
||||||
border-bottom: 4px solid transparent;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
border-inline-start: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
border-bottom: 4px solid $ui-highlight-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
display: block;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 11px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
|
||||||
display: block;
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: $primary-text-color;
|
|
||||||
|
|
||||||
@each $lang in $cjk-langs {
|
|
||||||
&:lang(#{$lang}) {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abbr {
|
|
||||||
color: $highlight-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-authorize {
|
|
||||||
padding: 14px 10px;
|
|
||||||
|
|
||||||
.detailed-status__display-name {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-authorize__avatar {
|
|
||||||
float: left;
|
|
||||||
margin-inline-end: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification__report {
|
|
||||||
padding: 8px 10px;
|
|
||||||
padding-inline-start: 68px;
|
|
||||||
position: relative;
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
min-height: 54px;
|
|
||||||
|
|
||||||
&__details {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
color: $darker-text-color;
|
|
||||||
font-size: 15px;
|
|
||||||
line-height: 22px;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__avatar {
|
|
||||||
position: absolute;
|
|
||||||
inset-inline-start: 10px;
|
|
||||||
top: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification__message {
|
|
||||||
margin-inline-start: 42px;
|
|
||||||
padding-top: 8px;
|
|
||||||
padding-inline-start: 26px;
|
|
||||||
cursor: default;
|
|
||||||
color: $darker-text-color;
|
|
||||||
font-size: 15px;
|
|
||||||
position: relative;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
color: $highlight-text-color;
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-star {
|
|
||||||
color: $gold-star;
|
|
||||||
}
|
|
||||||
|
|
||||||
> span {
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account--panel {
|
|
||||||
background: lighten($ui-base-color, 4%);
|
|
||||||
border-top: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
padding: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account--panel__button,
|
|
||||||
.detailed-status__button {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailed-status__button .emoji-button {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.relationship-tag {
|
|
||||||
color: $white;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
display: block;
|
|
||||||
background-color: rgba($black, 0.45);
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 500;
|
|
||||||
padding: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
opacity: 0.7;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-gallery__container {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
padding: 4px 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-gallery__item {
|
|
||||||
border: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 2px;
|
|
||||||
|
|
||||||
&__icons {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
inset-inline-start: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification__filter-bar,
|
|
||||||
.account__section-headline {
|
|
||||||
background: darken($ui-base-color, 4%);
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
cursor: default;
|
|
||||||
display: flex;
|
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
button {
|
|
||||||
background: transparent;
|
|
||||||
border: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
a {
|
|
||||||
display: block;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
color: $darker-text-color;
|
|
||||||
padding: 15px 0;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-align: center;
|
|
||||||
text-decoration: none;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: $primary-text-color;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
display: block;
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
bottom: -1px;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 3px;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: $highlight-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.directory__section-headline {
|
|
||||||
background: darken($ui-base-color, 2%);
|
|
||||||
border-bottom-color: transparent;
|
|
||||||
|
|
||||||
a,
|
|
||||||
button {
|
|
||||||
&.active {
|
|
||||||
&::before {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
border-color: transparent transparent darken($ui-base-color, 7%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__moved-note {
|
|
||||||
padding: 14px 10px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
background: lighten($ui-base-color, 4%);
|
|
||||||
border-top: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
|
|
||||||
&__message {
|
|
||||||
position: relative;
|
|
||||||
margin-inline-start: 58px;
|
|
||||||
color: $dark-text-color;
|
|
||||||
padding: 8px 0;
|
|
||||||
padding-top: 0;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
> span {
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__icon-wrapper {
|
|
||||||
inset-inline-start: -26px;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailed-status__display-avatar {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailed-status__display-name {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__header__content {
|
|
||||||
color: $darker-text-color;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 400;
|
|
||||||
overflow: hidden;
|
|
||||||
word-break: normal;
|
|
||||||
word-wrap: break-word;
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: underline;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__header {
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&.inactive {
|
|
||||||
opacity: 0.5;
|
|
||||||
|
|
||||||
.account__header__image,
|
|
||||||
.account__avatar {
|
|
||||||
filter: grayscale(100%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__info {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
inset-inline-start: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__image {
|
|
||||||
overflow: hidden;
|
|
||||||
height: 145px;
|
|
||||||
position: relative;
|
|
||||||
background: darken($ui-base-color, 4%);
|
|
||||||
|
|
||||||
img {
|
|
||||||
object-fit: cover;
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__bar {
|
|
||||||
position: relative;
|
|
||||||
background: lighten($ui-base-color, 4%);
|
|
||||||
padding: 5px;
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 12%);
|
|
||||||
|
|
||||||
.avatar {
|
|
||||||
display: block;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
width: 94px;
|
|
||||||
|
|
||||||
.account__avatar {
|
|
||||||
background: darken($ui-base-color, 8%);
|
|
||||||
border: 2px solid lighten($ui-base-color, 4%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__badges {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 8px;
|
|
||||||
|
|
||||||
.account-role {
|
|
||||||
line-height: unset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__tabs {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 7px 10px;
|
|
||||||
margin-top: -55px;
|
|
||||||
gap: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
margin-inline-start: -2px; // aligns the pfp with content below
|
|
||||||
|
|
||||||
&__buttons {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
padding-top: 55px;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
flex-shrink: 1;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
@media screen and (max-width: $no-gap-breakpoint) {
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
border: 1px solid lighten($ui-base-color, 12%);
|
|
||||||
border-radius: 4px;
|
|
||||||
box-sizing: content-box;
|
|
||||||
padding: 5px;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__name {
|
|
||||||
padding: 5px 10px;
|
|
||||||
|
|
||||||
.emojione {
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 24px;
|
|
||||||
color: $primary-text-color;
|
|
||||||
font-weight: 500;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
|
|
||||||
small {
|
|
||||||
display: block;
|
|
||||||
font-size: 14px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
font-weight: 400;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
|
|
||||||
span {
|
|
||||||
user-select: all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-lock {
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
position: relative;
|
|
||||||
top: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.spacer {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__bio {
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 0 -5px;
|
|
||||||
|
|
||||||
.account__header__content {
|
|
||||||
padding: 20px 15px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
color: $primary-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__header__joined {
|
|
||||||
font-size: 14px;
|
|
||||||
padding: 5px 15px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
|
|
||||||
.columns-area--mobile & {
|
|
||||||
padding-inline-start: 20px;
|
|
||||||
padding-inline-end: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__header__fields {
|
|
||||||
margin: 0;
|
|
||||||
border-top: 1px solid lighten($ui-base-color, 12%);
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: lighten($ui-highlight-color, 8%);
|
|
||||||
}
|
|
||||||
|
|
||||||
dl:first-child .verified {
|
|
||||||
border-radius: 0 4px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
dd {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.verified a {
|
|
||||||
color: $valid-value-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__extra {
|
|
||||||
margin-top: 4px;
|
|
||||||
|
|
||||||
&__links {
|
|
||||||
font-size: 14px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
padding: 10px 0;
|
|
||||||
|
|
||||||
a {
|
|
||||||
display: inline-block;
|
|
||||||
color: $darker-text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
padding: 5px 10px;
|
|
||||||
font-weight: 500;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 700;
|
|
||||||
color: $primary-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__account-note {
|
|
||||||
margin: 0 -5px;
|
|
||||||
padding: 10px 15px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 400;
|
|
||||||
border-top: 1px solid lighten($ui-base-color, 12%);
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 12%);
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: block;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: $darker-text-color;
|
|
||||||
text-transform: uppercase;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__content {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
padding: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: calc(100% + 20px);
|
|
||||||
color: $secondary-text-color;
|
|
||||||
background: $ui-base-color;
|
|
||||||
padding: 10px;
|
|
||||||
margin: 0 -10px;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: 14px;
|
|
||||||
resize: none;
|
|
||||||
border: 0;
|
|
||||||
outline: 0;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
color: $dark-text-color;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__contents {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__details {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
column-gap: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.verified-badge {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
color: $valid-value-color;
|
|
||||||
gap: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
> span {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
font-weight: 500;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.moved-account-banner,
|
|
||||||
.follow-request-banner,
|
|
||||||
.account-memorial-banner {
|
|
||||||
padding: 20px;
|
|
||||||
background: lighten($ui-base-color, 4%);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
&__message {
|
|
||||||
color: $darker-text-color;
|
|
||||||
padding: 8px 0;
|
|
||||||
padding-top: 0;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__action {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
gap: 15px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailed-status__display-name {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.follow-request-banner .button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-memorial-banner__message {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
|
@ -1,233 +0,0 @@
|
||||||
.announcements__item__content {
|
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
.emojione {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin: -3px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: $secondary-text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.mention {
|
|
||||||
&:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
span {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.unhandled-link {
|
|
||||||
color: $highlight-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.announcements {
|
|
||||||
background: lighten($ui-base-color, 8%);
|
|
||||||
font-size: 13px;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-end;
|
|
||||||
|
|
||||||
&__mastodon {
|
|
||||||
width: 124px;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
|
|
||||||
@media screen and (max-width: 124px + 300px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__container {
|
|
||||||
width: calc(100% - 124px);
|
|
||||||
flex: 0 0 auto;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
@media screen and (max-width: 124px + 300px) {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item {
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%;
|
|
||||||
padding: 15px;
|
|
||||||
position: relative;
|
|
||||||
font-size: 15px;
|
|
||||||
line-height: 20px;
|
|
||||||
word-wrap: break-word;
|
|
||||||
font-weight: 400;
|
|
||||||
max-height: 50vh;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
&__range {
|
|
||||||
display: block;
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
padding-inline-end: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__unread {
|
|
||||||
position: absolute;
|
|
||||||
top: 19px;
|
|
||||||
inset-inline-end: 19px;
|
|
||||||
display: block;
|
|
||||||
background: $highlight-text-color;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 0.625rem;
|
|
||||||
height: 0.625rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__pagination {
|
|
||||||
padding: 15px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 3px;
|
|
||||||
inset-inline-end: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.layout-multiple-columns .announcements__mastodon {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layout-multiple-columns .announcements__container {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reactions-bar {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: 15px;
|
|
||||||
margin-inline-start: -2px;
|
|
||||||
width: calc(100% - (90px - 33px));
|
|
||||||
|
|
||||||
&__item {
|
|
||||||
flex-shrink: 0;
|
|
||||||
background: lighten($ui-base-color, 12%);
|
|
||||||
border: 0;
|
|
||||||
border-radius: 3px;
|
|
||||||
margin: 2px;
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
padding: 0 6px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
transition: all 100ms ease-in;
|
|
||||||
transition-property: background-color, color;
|
|
||||||
|
|
||||||
&__emoji {
|
|
||||||
display: block;
|
|
||||||
margin: 3px 0;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
|
|
||||||
img {
|
|
||||||
display: block;
|
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
min-width: auto;
|
|
||||||
min-height: auto;
|
|
||||||
vertical-align: bottom;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__count {
|
|
||||||
display: block;
|
|
||||||
min-width: 9px;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-align: center;
|
|
||||||
margin-inline-start: 6px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
background: lighten($ui-base-color, 16%);
|
|
||||||
transition: all 200ms ease-out;
|
|
||||||
transition-property: background-color, color;
|
|
||||||
|
|
||||||
&__count {
|
|
||||||
color: lighten($darker-text-color, 4%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
transition: all 100ms ease-in;
|
|
||||||
transition-property: background-color, color;
|
|
||||||
background-color: mix(
|
|
||||||
lighten($ui-base-color, 12%),
|
|
||||||
$ui-highlight-color,
|
|
||||||
80%
|
|
||||||
);
|
|
||||||
|
|
||||||
.reactions-bar__item__count {
|
|
||||||
color: lighten($highlight-text-color, 8%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-picker-dropdown {
|
|
||||||
margin: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover .emoji-button {
|
|
||||||
opacity: 0.85;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-button {
|
|
||||||
color: $darker-text-color;
|
|
||||||
margin: 0;
|
|
||||||
font-size: 16px;
|
|
||||||
width: auto;
|
|
||||||
flex-shrink: 0;
|
|
||||||
padding: 0 6px;
|
|
||||||
height: 22px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
opacity: 0.5;
|
|
||||||
transition: all 100ms ease-in;
|
|
||||||
transition-property: background-color, color;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
opacity: 1;
|
|
||||||
color: lighten($darker-text-color, 4%);
|
|
||||||
transition: all 200ms ease-out;
|
|
||||||
transition-property: background-color, color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--empty {
|
|
||||||
.emoji-button {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,674 +0,0 @@
|
||||||
.compose-form {
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
.emoji-picker-dropdown {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
inset-inline-end: 0;
|
|
||||||
|
|
||||||
::-webkit-scrollbar-track:hover,
|
|
||||||
::-webkit-scrollbar-track:active {
|
|
||||||
background-color: rgba($base-overlay-background, 0.3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.character-counter {
|
|
||||||
cursor: default;
|
|
||||||
font-family: $font-sans-serif, sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: $lighter-text-color;
|
|
||||||
|
|
||||||
&.character-counter--over {
|
|
||||||
color: $warning-red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-reduce-motion .spoiler-input {
|
|
||||||
transition:
|
|
||||||
height 0.4s ease,
|
|
||||||
opacity 0.4s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spoiler-input {
|
|
||||||
height: 0;
|
|
||||||
transform-origin: bottom;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
&.spoiler-input--visible {
|
|
||||||
height: 36px;
|
|
||||||
margin-bottom: 11px;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 10px;
|
|
||||||
width: 100%;
|
|
||||||
outline: 0;
|
|
||||||
color: $inverted-text-color;
|
|
||||||
background: $simple-background-color;
|
|
||||||
font-size: 14px;
|
|
||||||
font-family: inherit;
|
|
||||||
resize: vertical;
|
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
color: $dark-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
@include single-column('screen and (max-width: 630px)') {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__warning {
|
|
||||||
color: $inverted-text-color;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
background: $ui-primary-color;
|
|
||||||
box-shadow: 0 2px 6px rgba($base-shadow-color, 0.3);
|
|
||||||
padding: 8px 10px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 400;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: $lighter-text-color;
|
|
||||||
font-weight: 500;
|
|
||||||
text-decoration: underline;
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:focus,
|
|
||||||
&:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__sensitive-button {
|
|
||||||
padding: 10px;
|
|
||||||
padding-top: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: $highlight-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type='checkbox'] {
|
|
||||||
appearance: none;
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
border: 1px solid $ui-primary-color;
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
margin-inline-start: 5px;
|
|
||||||
margin-inline-end: 10px;
|
|
||||||
top: -1px;
|
|
||||||
border-radius: 4px;
|
|
||||||
vertical-align: middle;
|
|
||||||
cursor: inherit;
|
|
||||||
|
|
||||||
&:checked {
|
|
||||||
border-color: $highlight-text-color;
|
|
||||||
background: $highlight-text-color
|
|
||||||
url("data:image/svg+xml;utf8,<svg width='18' height='18' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M4.5 8.5L8 12l6-6' stroke='white' stroke-width='1.5'/></svg>")
|
|
||||||
center center no-repeat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.quote-indicator,
|
|
||||||
.reply-indicator {
|
|
||||||
margin: 0 0 10px;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 10px;
|
|
||||||
background: $ui-primary-color;
|
|
||||||
min-height: 23px;
|
|
||||||
overflow-y: auto;
|
|
||||||
flex: 0 2 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quote-indicator__header,
|
|
||||||
.reply-indicator__header {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quote-indicator__cancel,
|
|
||||||
.reply-indicator__cancel {
|
|
||||||
float: right;
|
|
||||||
line-height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quote-indicator__display-name,
|
|
||||||
.reply-indicator__display-name {
|
|
||||||
color: $inverted-text-color;
|
|
||||||
display: block;
|
|
||||||
max-width: 100%;
|
|
||||||
line-height: 24px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
& > .display-name {
|
|
||||||
line-height: unset;
|
|
||||||
height: unset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.quote-indicator__display-avatar,
|
|
||||||
.reply-indicator__display-avatar {
|
|
||||||
float: left;
|
|
||||||
margin-inline-end: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quote-indicator__content,
|
|
||||||
.reply-indicator__content {
|
|
||||||
position: relative;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 20px;
|
|
||||||
word-wrap: break-word;
|
|
||||||
font-weight: 400;
|
|
||||||
overflow: hidden;
|
|
||||||
padding-top: 5px;
|
|
||||||
color: $inverted-text-color;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
|
|
||||||
p,
|
|
||||||
pre {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: $lighter-text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.mention {
|
|
||||||
&:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
span {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.emojione {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin: -5px 0 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form .compose-form__autosuggest-wrapper {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form .autosuggest-textarea,
|
|
||||||
.compose-form .autosuggest-input {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
label {
|
|
||||||
.autosuggest-textarea__textarea {
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 4px 4px 0 0;
|
|
||||||
padding: 10px 32px 0 10px;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 100px;
|
|
||||||
outline: 0;
|
|
||||||
color: $inverted-text-color;
|
|
||||||
background: $simple-background-color;
|
|
||||||
font-size: 14px;
|
|
||||||
font-family: inherit;
|
|
||||||
resize: none;
|
|
||||||
scrollbar-color: initial;
|
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
color: $dark-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
all: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include single-column('screen and (max-width: 630px)') {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include limited-single-column('screen and (max-width: 600px)') {
|
|
||||||
height: 100px !important; // prevent auto-resize textarea
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__textarea-icons {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 29px;
|
|
||||||
inset-inline-end: 5px;
|
|
||||||
bottom: 5px;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
& > .textarea_icon {
|
|
||||||
display: block;
|
|
||||||
margin-top: 2px;
|
|
||||||
margin-inline-start: 2px;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
color: $lighter-text-color;
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 24px;
|
|
||||||
text-align: center;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-textarea__suggestions-wrapper {
|
|
||||||
position: relative;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-textarea__suggestions {
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 99;
|
|
||||||
box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);
|
|
||||||
background: $ui-secondary-color;
|
|
||||||
border-radius: 0 0 4px 4px;
|
|
||||||
color: $inverted-text-color;
|
|
||||||
font-size: 14px;
|
|
||||||
padding: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-textarea__suggestions--visible {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-textarea__suggestions__item {
|
|
||||||
padding: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active,
|
|
||||||
&.selected {
|
|
||||||
background: darken($ui-secondary-color, 10%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-account,
|
|
||||||
.autosuggest-emoji,
|
|
||||||
.autosuggest-hashtag {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
line-height: 18px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-hashtag {
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
&__name {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__uses {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
text-align: end;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-account-icon,
|
|
||||||
.autosuggest-emoji img {
|
|
||||||
margin-inline-end: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-account .display-name > span {
|
|
||||||
color: $lighter-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__upload-wrapper {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__uploads-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
font-family: inherit;
|
|
||||||
padding: 5px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__upload {
|
|
||||||
flex: 1 1 0;
|
|
||||||
margin: 5px;
|
|
||||||
min-width: 40%;
|
|
||||||
|
|
||||||
.compose-form__upload-thumbnail {
|
|
||||||
position: relative;
|
|
||||||
border-radius: 4px;
|
|
||||||
height: 140px;
|
|
||||||
width: 100%;
|
|
||||||
background-color: $base-shadow-color;
|
|
||||||
background-position: center;
|
|
||||||
background-size: cover;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
& > .close {
|
|
||||||
mix-blend-mode: difference;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
flex: 0 1 auto;
|
|
||||||
color: $secondary-text-color;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
padding: 10px;
|
|
||||||
font-family: inherit;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
color: lighten($secondary-text-color, 7%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__warning {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 2;
|
|
||||||
bottom: 0;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
inset-inline-end: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background: linear-gradient(
|
|
||||||
0deg,
|
|
||||||
rgba($base-shadow-color, 0.8) 0,
|
|
||||||
rgba($base-shadow-color, 0.35) 80%,
|
|
||||||
transparent
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__upload__actions {
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
rgba($base-shadow-color, 0.8) 0,
|
|
||||||
rgba($base-shadow-color, 0.35) 80%,
|
|
||||||
transparent
|
|
||||||
);
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-progress {
|
|
||||||
display: flex;
|
|
||||||
padding: 10px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
overflow: hidden;
|
|
||||||
gap: 10px;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
display: block;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-progress__message {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-progress__backdrop {
|
|
||||||
position: relative;
|
|
||||||
margin-top: 5px;
|
|
||||||
border-radius: 6px;
|
|
||||||
width: 100%;
|
|
||||||
height: 6px;
|
|
||||||
background: darken($simple-background-color, 8%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-progress__tracker {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
height: 6px;
|
|
||||||
border-radius: 6px;
|
|
||||||
background: $ui-highlight-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__modifiers {
|
|
||||||
color: $inverted-text-color;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: 14px;
|
|
||||||
background: $simple-background-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__buttons-wrapper {
|
|
||||||
padding: 10px;
|
|
||||||
background: darken($simple-background-color, 8%);
|
|
||||||
border-radius: 0 0 4px 4px;
|
|
||||||
height: 27px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__buttons {
|
|
||||||
display: flex;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
gap: 2px;
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .icon-button,
|
|
||||||
& .text-icon-button {
|
|
||||||
box-sizing: content-box;
|
|
||||||
padding: 0 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.character-counter__wrapper {
|
|
||||||
align-self: center;
|
|
||||||
margin-inline-end: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.privacy-dropdown__dropdown {
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: var(--dropdown-shadow);
|
|
||||||
background: $simple-background-color;
|
|
||||||
overflow: hidden;
|
|
||||||
transform-origin: 50% 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.privacy-dropdown__option {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 10px;
|
|
||||||
color: $inverted-text-color;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.privacy-dropdown__option__content {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
color: $lighter-text-color;
|
|
||||||
|
|
||||||
&:not(:first-child) {
|
|
||||||
margin-inline-start: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
|
||||||
display: block;
|
|
||||||
color: $inverted-text-color;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&.active {
|
|
||||||
background: $ui-highlight-color;
|
|
||||||
color: $primary-text-color;
|
|
||||||
|
|
||||||
.privacy-dropdown__option__content {
|
|
||||||
color: $primary-text-color;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
color: $primary-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active:hover {
|
|
||||||
background: lighten($ui-highlight-color, 4%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__publish {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
min-width: 0;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
column-gap: 5px;
|
|
||||||
|
|
||||||
.compose-form__publish-button-wrapper {
|
|
||||||
padding-top: 10px;
|
|
||||||
|
|
||||||
button {
|
|
||||||
padding: 7px 10px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
display: flex;
|
|
||||||
gap: 5px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.side_arm {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.language-dropdown {
|
|
||||||
&__dropdown {
|
|
||||||
background: $simple-background-color;
|
|
||||||
box-shadow: var(--dropdown-shadow);
|
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: 2;
|
|
||||||
|
|
||||||
&.top {
|
|
||||||
transform-origin: 50% 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.bottom {
|
|
||||||
transform-origin: 50% 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-search {
|
|
||||||
padding-inline-end: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-search-icon {
|
|
||||||
inset-inline-end: 10px + 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-scroll {
|
|
||||||
padding: 0 10px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__results {
|
|
||||||
&__item {
|
|
||||||
cursor: pointer;
|
|
||||||
color: $inverted-text-color;
|
|
||||||
font-weight: 500;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 4px;
|
|
||||||
display: flex;
|
|
||||||
gap: 6px;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&:focus,
|
|
||||||
&:active,
|
|
||||||
&:hover {
|
|
||||||
background: $ui-secondary-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__common-name {
|
|
||||||
color: $darker-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background: $ui-highlight-color;
|
|
||||||
color: $primary-text-color;
|
|
||||||
outline: 0;
|
|
||||||
|
|
||||||
.language-dropdown__dropdown__results__item__common-name {
|
|
||||||
color: $secondary-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: lighten($ui-highlight-color, 4%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
.scrollable .account-card {
|
|
||||||
margin: 10px;
|
|
||||||
background: lighten($ui-base-color, 8%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrollable .account-card__title__avatar {
|
|
||||||
img,
|
|
||||||
.account__avatar {
|
|
||||||
border-color: lighten($ui-base-color, 8%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrollable .account-card__bio::after {
|
|
||||||
background: linear-gradient(
|
|
||||||
to left,
|
|
||||||
lighten($ui-base-color, 8%),
|
|
||||||
transparent
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-form {
|
|
||||||
background: $ui-base-color;
|
|
||||||
|
|
||||||
&__column {
|
|
||||||
padding: 10px 15px;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-button {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-button {
|
|
||||||
font-size: 14px;
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 6px 0;
|
|
||||||
line-height: 18px;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
input[type='radio'],
|
|
||||||
input[type='checkbox'] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__input {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
border: 1px solid $ui-primary-color;
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
margin-inline-end: 10px;
|
|
||||||
top: -1px;
|
|
||||||
border-radius: 50%;
|
|
||||||
vertical-align: middle;
|
|
||||||
|
|
||||||
&.checked {
|
|
||||||
border-color: lighten($ui-highlight-color, 4%);
|
|
||||||
background: lighten($ui-highlight-color, 4%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
.domain {
|
|
||||||
padding: 10px;
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
|
|
||||||
.domain__domain-name {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
display: block;
|
|
||||||
color: $primary-text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.domain__wrapper {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.domain_buttons {
|
|
||||||
height: 18px;
|
|
||||||
padding: 10px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
|
@ -1,309 +0,0 @@
|
||||||
.drawer {
|
|
||||||
width: 300px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow-y: hidden;
|
|
||||||
padding: 10px 5px;
|
|
||||||
flex: none;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
padding-inline-start: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
padding-inline-end: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include single-column('screen and (max-width: 630px)') {
|
|
||||||
flex: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include limited-single-column('screen and (max-width: 630px)') {
|
|
||||||
&,
|
|
||||||
&:first-child,
|
|
||||||
&:last-child {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.wide & {
|
|
||||||
min-width: 300px;
|
|
||||||
max-width: 400px;
|
|
||||||
flex: 1 1 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include single-column('screen and (max-width: 630px)') {
|
|
||||||
:root & {
|
|
||||||
// Overrides `.wide` for single-column view
|
|
||||||
flex: auto;
|
|
||||||
width: 100%;
|
|
||||||
min-width: 0;
|
|
||||||
max-width: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-swipeable-view-container & {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__tab {
|
|
||||||
display: flex;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
padding: 13px 3px 11px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 16px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border-bottom: 2px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__header {
|
|
||||||
flex: none;
|
|
||||||
font-size: 16px;
|
|
||||||
background: $ui-base-color;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
background: lighten($ui-base-color, 3%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search {
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
flex: none;
|
|
||||||
|
|
||||||
@include limited-single-column(
|
|
||||||
'screen and (max-width: #{$no-gap-breakpoint})'
|
|
||||||
) {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
@include single-column('screen and (max-width: 630px)') {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.navigation-bar {
|
|
||||||
padding: 10px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.acct {
|
|
||||||
display: block;
|
|
||||||
color: $secondary-text-color;
|
|
||||||
font-weight: 500;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navigation-bar__actions {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.compose__action-bar .icon-button {
|
|
||||||
pointer-events: auto;
|
|
||||||
transform: scale(1, 1) translate(0, 0);
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.navigation-bar__profile {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
margin-inline-start: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer--results {
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-results__section {
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__header {
|
|
||||||
background: darken($ui-base-color, 4%);
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
padding: 15px;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 14px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
color: $highlight-text-color;
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
background: 0;
|
|
||||||
font: inherit;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account:last-child,
|
|
||||||
& > div:last-child .status {
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .hashtag {
|
|
||||||
display: block;
|
|
||||||
padding: 10px;
|
|
||||||
color: $secondary-text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
color: lighten($secondary-text-color, 4%);
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__pager {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0;
|
|
||||||
flex-grow: 1;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__inner {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
background: $ui-base-color;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
overflow-y: auto;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
&.darker {
|
|
||||||
background: $ui-base-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__inner__mastodon {
|
|
||||||
background: $ui-base-color
|
|
||||||
url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-color)}"/></svg>')
|
|
||||||
no-repeat bottom / 100% auto;
|
|
||||||
flex: 1;
|
|
||||||
min-height: 47px;
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
> img {
|
|
||||||
display: block;
|
|
||||||
object-fit: contain;
|
|
||||||
object-position: bottom left;
|
|
||||||
width: 85%;
|
|
||||||
height: 100%;
|
|
||||||
pointer-events: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .mastodon {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 0;
|
|
||||||
cursor: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (height >= 640px) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.pseudo-drawer {
|
|
||||||
background: lighten($ui-base-color, 13%);
|
|
||||||
font-size: 13px;
|
|
||||||
text-align: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__backdrop {
|
|
||||||
cursor: pointer;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: rgba($base-overlay-background, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
@for $i from 0 through 3 {
|
|
||||||
.mbstobon-#{$i} .drawer__inner__mastodon {
|
|
||||||
@if $i == 3 {
|
|
||||||
background:
|
|
||||||
url('~flavours/glitch/images/wave-drawer.png')
|
|
||||||
no-repeat
|
|
||||||
bottom /
|
|
||||||
100%
|
|
||||||
auto,
|
|
||||||
$ui-base-color;
|
|
||||||
} @else {
|
|
||||||
background:
|
|
||||||
url('~flavours/glitch/images/wave-drawer-glitched.png')
|
|
||||||
no-repeat
|
|
||||||
bottom /
|
|
||||||
100%
|
|
||||||
auto,
|
|
||||||
$ui-base-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .mastodon {
|
|
||||||
background: url('~flavours/glitch/images/mbstobon-ui-#{$i}.png')
|
|
||||||
no-repeat
|
|
||||||
left
|
|
||||||
bottom /
|
|
||||||
contain;
|
|
||||||
|
|
||||||
@if $i != 3 {
|
|
||||||
filter: contrast(50%) brightness(50%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
.emojione {
|
|
||||||
font-size: inherit;
|
|
||||||
vertical-align: middle;
|
|
||||||
object-fit: contain;
|
|
||||||
margin: -0.2ex 0.15em 0.2ex;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-picker-dropdown__menu {
|
|
||||||
background: $simple-background-color;
|
|
||||||
position: relative;
|
|
||||||
box-shadow: var(--dropdown-shadow);
|
|
||||||
border-radius: 4px;
|
|
||||||
margin-top: 5px;
|
|
||||||
z-index: 2;
|
|
||||||
|
|
||||||
.emoji-mart-scroll {
|
|
||||||
transition: opacity 200ms ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.selecting .emoji-mart-scroll {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-picker-dropdown__modifiers {
|
|
||||||
position: absolute;
|
|
||||||
top: 60px;
|
|
||||||
inset-inline-end: 11px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-picker-dropdown__modifiers__menu {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 4;
|
|
||||||
top: -4px;
|
|
||||||
inset-inline-start: -8px;
|
|
||||||
background: $simple-background-color;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
button {
|
|
||||||
display: block;
|
|
||||||
cursor: pointer;
|
|
||||||
border: 0;
|
|
||||||
padding: 4px 8px;
|
|
||||||
background: transparent;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
background: rgba($ui-secondary-color, 0.4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-emoji {
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-emoji {
|
|
||||||
span {
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-button {
|
|
||||||
display: block;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 2px;
|
|
||||||
padding-inline-start: 2px;
|
|
||||||
padding-inline-end: 5px;
|
|
||||||
outline: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
img {
|
|
||||||
filter: grayscale(100%);
|
|
||||||
opacity: 0.8;
|
|
||||||
display: block;
|
|
||||||
margin: 0;
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
img {
|
|
||||||
opacity: 1;
|
|
||||||
filter: none;
|
|
||||||
border-radius: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus-visible {
|
|
||||||
img {
|
|
||||||
outline: $ui-button-icon-focus-outline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,143 +0,0 @@
|
||||||
.account-card__header {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.explore__search-header {
|
|
||||||
background: darken($ui-base-color, 4%);
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: 15px;
|
|
||||||
|
|
||||||
.search {
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search__input {
|
|
||||||
border: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search__popout {
|
|
||||||
border: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search .icon {
|
|
||||||
top: 9px;
|
|
||||||
inset-inline-end: 10px;
|
|
||||||
color: $dark-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.explore__search-results {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background: $ui-base-color;
|
|
||||||
border-bottom-left-radius: 4px;
|
|
||||||
border-bottom-right-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.story {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
color: $primary-text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
padding: 15px;
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
gap: 15px;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
color: $highlight-text-color;
|
|
||||||
|
|
||||||
.story__details__publisher,
|
|
||||||
.story__details__shared {
|
|
||||||
color: $highlight-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__details {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
|
|
||||||
&__publisher {
|
|
||||||
color: $darker-text-color;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
font-size: 19px;
|
|
||||||
line-height: 24px;
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__shared {
|
|
||||||
color: $darker-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__thumbnail {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
position: relative;
|
|
||||||
width: 120px;
|
|
||||||
height: 120px;
|
|
||||||
|
|
||||||
.skeleton {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
border-radius: 8px;
|
|
||||||
display: block;
|
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__preview {
|
|
||||||
border-radius: 8px;
|
|
||||||
display: block;
|
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: fill;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
z-index: 0;
|
|
||||||
|
|
||||||
&--hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.expanded {
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.story__thumbnail {
|
|
||||||
order: 1;
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
aspect-ratio: 1.91 / 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.story__details {
|
|
||||||
order: 2;
|
|
||||||
width: 100%;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
@import 'misc';
|
|
||||||
@import 'accounts';
|
|
||||||
@import 'domains';
|
|
||||||
@import 'status';
|
|
||||||
@import 'modal';
|
|
||||||
@import 'compose_form';
|
|
||||||
@import 'columns';
|
|
||||||
@import 'regeneration_indicator';
|
|
||||||
@import 'directory';
|
|
||||||
@import 'search';
|
|
||||||
@import 'emoji';
|
|
||||||
@import 'doodle';
|
|
||||||
@import 'drawer';
|
|
||||||
@import 'media';
|
|
||||||
@import 'sensitive';
|
|
||||||
@import 'lists';
|
|
||||||
@import 'emoji_picker';
|
|
||||||
@import 'local_settings';
|
|
||||||
@import 'single_column';
|
|
||||||
@import 'announcements';
|
|
||||||
@import 'explore';
|
|
||||||
@import 'signed_out';
|
|
||||||
@import 'privacy_policy';
|
|
||||||
@import 'about';
|
|
|
@ -1,94 +0,0 @@
|
||||||
.list-editor {
|
|
||||||
background: $ui-base-color;
|
|
||||||
flex-direction: column;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
|
||||||
width: 380px;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
@media screen and (width <= 420px) {
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
padding: 15px 0;
|
|
||||||
background: lighten($ui-base-color, 13%);
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 16px;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 8px 8px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__pager {
|
|
||||||
height: 50vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__inner {
|
|
||||||
border-radius: 0 0 8px 8px;
|
|
||||||
|
|
||||||
&.backdrop {
|
|
||||||
width: calc(100% - 60px);
|
|
||||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
|
||||||
border-radius: 0 0 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__accounts {
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__display-name {
|
|
||||||
&:hover strong {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__avatar {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-adder {
|
|
||||||
background: $ui-base-color;
|
|
||||||
flex-direction: column;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
|
||||||
width: 380px;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
@media screen and (width <= 420px) {
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__account {
|
|
||||||
background: lighten($ui-base-color, 13%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__lists {
|
|
||||||
background: lighten($ui-base-color, 13%);
|
|
||||||
height: 50vh;
|
|
||||||
border-radius: 0 0 8px 8px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list {
|
|
||||||
padding: 10px;
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.list__wrapper {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list__display-name {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
overflow: hidden;
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 16px;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,802 +0,0 @@
|
||||||
.video-error-cover {
|
|
||||||
align-items: center;
|
|
||||||
background: $base-overlay-background;
|
|
||||||
color: $primary-text-color;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 8px;
|
|
||||||
position: relative;
|
|
||||||
text-align: center;
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-spoiler {
|
|
||||||
background: $base-overlay-background;
|
|
||||||
color: $darker-text-color;
|
|
||||||
border: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
color: lighten($darker-text-color, 8%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status__content > & {
|
|
||||||
margin-top: 15px; // Add margin when used bare for NSFW video player
|
|
||||||
}
|
|
||||||
@include fullwidth-gallery;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-spoiler__warning {
|
|
||||||
display: block;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-spoiler__trigger {
|
|
||||||
display: block;
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-gallery__item__badges {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 6px;
|
|
||||||
inset-inline-start: 6px;
|
|
||||||
display: flex;
|
|
||||||
gap: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-gallery__alt__label,
|
|
||||||
.media-gallery__gifv__label {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
color: $white;
|
|
||||||
background: rgba($black, 0.65);
|
|
||||||
padding: 2px 6px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 700;
|
|
||||||
z-index: 1;
|
|
||||||
pointer-events: none;
|
|
||||||
line-height: 18px;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-gallery {
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin-top: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: 4px;
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 64px;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 50% 50%;
|
|
||||||
grid-template-rows: 50% 50%;
|
|
||||||
gap: 2px;
|
|
||||||
|
|
||||||
@include fullwidth-gallery;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-gallery__item {
|
|
||||||
border: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&--tall {
|
|
||||||
grid-row: span 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--wide {
|
|
||||||
grid-column: span 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-width & {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.letterbox {
|
|
||||||
background: $base-shadow-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-gallery__item-thumbnail {
|
|
||||||
cursor: zoom-in;
|
|
||||||
display: block;
|
|
||||||
text-decoration: none;
|
|
||||||
color: $secondary-text-color;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
&,
|
|
||||||
img {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
|
|
||||||
&:not(.letterbox) {
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-gallery__preview {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
z-index: 0;
|
|
||||||
background: $base-overlay-background;
|
|
||||||
|
|
||||||
&--hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-gallery__gifv {
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-gallery__item-gifv-thumbnail {
|
|
||||||
cursor: zoom-in;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
&:not(.letterbox) {
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-gallery__item-thumbnail-label {
|
|
||||||
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
|
|
||||||
clip: rect(1px, 1px, 1px, 1px);
|
|
||||||
overflow: hidden;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-modal__container {
|
|
||||||
max-width: 100vw;
|
|
||||||
max-height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.audio-modal__container {
|
|
||||||
width: 50vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-modal {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&__close,
|
|
||||||
&__zoom-button {
|
|
||||||
color: rgba($white, 0.7);
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
color: $white;
|
|
||||||
background-color: rgba($white, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
background-color: rgba($white, 0.3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-modal__closer {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
inset-inline-end: 0;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-modal__navigation {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
inset-inline-end: 0;
|
|
||||||
bottom: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
transition: opacity 0.3s linear;
|
|
||||||
will-change: opacity;
|
|
||||||
|
|
||||||
* {
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.media-modal__navigation--hidden {
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
* {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-modal__nav {
|
|
||||||
background: transparent;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 0;
|
|
||||||
color: rgba($white, 0.7);
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 24px;
|
|
||||||
height: 20vmax;
|
|
||||||
margin: auto 0;
|
|
||||||
padding: 30px 15px;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
color: $white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-modal__nav--left {
|
|
||||||
inset-inline-start: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-modal__nav--right {
|
|
||||||
inset-inline-end: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-modal__overlay {
|
|
||||||
max-width: 600px;
|
|
||||||
position: absolute;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
inset-inline-end: 0;
|
|
||||||
bottom: 0;
|
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
.picture-in-picture__footer {
|
|
||||||
border-radius: 0;
|
|
||||||
background: transparent;
|
|
||||||
padding: 20px 0;
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
color: $white;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
color: $white;
|
|
||||||
background-color: rgba($white, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
background-color: rgba($white, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: $highlight-text-color;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
background: rgba($highlight-text-color, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
background: rgba($highlight-text-color, 0.3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.star-icon.active {
|
|
||||||
color: $gold-star;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
background: rgba($gold-star, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
background: rgba($gold-star, 0.3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disabled {
|
|
||||||
color: $white;
|
|
||||||
background-color: transparent;
|
|
||||||
cursor: default;
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-modal__pagination {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-modal__page-dot {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
background-color: $white;
|
|
||||||
opacity: 0.4;
|
|
||||||
height: 6px;
|
|
||||||
width: 6px;
|
|
||||||
border-radius: 50%;
|
|
||||||
margin: 0 4px;
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
font-size: 0;
|
|
||||||
transition: opacity 0.2s ease-in-out;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-modal__close {
|
|
||||||
position: absolute;
|
|
||||||
inset-inline-end: 8px;
|
|
||||||
top: 8px;
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailed,
|
|
||||||
.fullscreen {
|
|
||||||
.video-player__volume__current,
|
|
||||||
.video-player__volume::before {
|
|
||||||
bottom: 27px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__volume__handle {
|
|
||||||
bottom: 23px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.audio-player {
|
|
||||||
overflow: hidden;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: relative;
|
|
||||||
background: darken($ui-base-color, 8%);
|
|
||||||
border-radius: 4px;
|
|
||||||
padding-bottom: 44px;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&.editable {
|
|
||||||
border-radius: 0;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.inactive {
|
|
||||||
audio,
|
|
||||||
.video-player__controls {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__volume::before,
|
|
||||||
.video-player__seek::before {
|
|
||||||
background: currentColor;
|
|
||||||
opacity: 0.15;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__seek__buffer {
|
|
||||||
background: currentColor;
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__buttons button,
|
|
||||||
.video-player__buttons a {
|
|
||||||
color: currentColor;
|
|
||||||
opacity: 0.75;
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
color: currentColor;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__time-sep,
|
|
||||||
.video-player__time-total,
|
|
||||||
.video-player__time-current {
|
|
||||||
color: currentColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__seek::before,
|
|
||||||
.video-player__seek__buffer,
|
|
||||||
.video-player__seek__progress {
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__seek__handle {
|
|
||||||
top: -4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__controls {
|
|
||||||
padding-top: 10px;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player {
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
background: $base-shadow-color;
|
|
||||||
max-width: 100%;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
color: $white;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&.editable {
|
|
||||||
border-radius: 0;
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailed-status & {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include fullwidth-gallery;
|
|
||||||
|
|
||||||
video {
|
|
||||||
display: block;
|
|
||||||
max-width: 100vw;
|
|
||||||
max-height: 80vh;
|
|
||||||
z-index: 1;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fullscreen {
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100% !important;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
video {
|
|
||||||
max-width: 100% !important;
|
|
||||||
max-height: 100% !important;
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100% !important;
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.inline {
|
|
||||||
video {
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__controls {
|
|
||||||
position: absolute;
|
|
||||||
direction: ltr;
|
|
||||||
z-index: 2;
|
|
||||||
bottom: 0;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
inset-inline-end: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background: linear-gradient(
|
|
||||||
0deg,
|
|
||||||
rgba($base-shadow-color, 0.85) 0,
|
|
||||||
rgba($base-shadow-color, 0.45) 60%,
|
|
||||||
transparent
|
|
||||||
);
|
|
||||||
padding: 0 15px;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.1s ease;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.inactive {
|
|
||||||
video,
|
|
||||||
.video-player__controls {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__spoiler {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
z-index: 4;
|
|
||||||
border: 0;
|
|
||||||
background: $base-shadow-color;
|
|
||||||
color: $darker-text-color;
|
|
||||||
transition: none;
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
display: block;
|
|
||||||
pointer-events: auto;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
color: lighten($darker-text-color, 7%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
display: block;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__subtitle {
|
|
||||||
display: block;
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buttons-bar {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
|
|
||||||
.video-player__download__icon {
|
|
||||||
color: inherit;
|
|
||||||
|
|
||||||
.fa,
|
|
||||||
&:active .fa,
|
|
||||||
&:hover .fa,
|
|
||||||
&:focus .fa {
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buttons {
|
|
||||||
display: flex;
|
|
||||||
flex: 0 1 auto;
|
|
||||||
min-width: 30px;
|
|
||||||
align-items: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
gap: 5px;
|
|
||||||
|
|
||||||
.player-button {
|
|
||||||
display: inline-block;
|
|
||||||
outline: 0;
|
|
||||||
padding: 5px;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
background: transparent;
|
|
||||||
border: 0;
|
|
||||||
color: rgba($white, 0.75);
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
color: $white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time {
|
|
||||||
display: inline;
|
|
||||||
flex: 0 1 auto;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
margin: 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-sep,
|
|
||||||
&__time-total,
|
|
||||||
&__time-current {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-current {
|
|
||||||
color: $white;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-sep {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-sep,
|
|
||||||
&__time-total {
|
|
||||||
color: $white;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__volume {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
display: inline-flex;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 24px;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.no-reduce-motion & {
|
|
||||||
transition: all 100ms linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
overflow: visible;
|
|
||||||
width: 50px;
|
|
||||||
margin-inline-end: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
width: 50px;
|
|
||||||
background: rgba($white, 0.35);
|
|
||||||
border-radius: 4px;
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
height: 4px;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(0, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__current {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
height: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(0, -50%);
|
|
||||||
background: lighten($ui-highlight-color, 8%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__handle {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 3;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
top: 50%;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
margin-inline-start: -6px;
|
|
||||||
transform: translate(0, -50%);
|
|
||||||
background: lighten($ui-highlight-color, 8%);
|
|
||||||
box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
.no-reduce-motion & {
|
|
||||||
transition: opacity 100ms linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active &__handle {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
padding: 2px 10px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: $white;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__seek {
|
|
||||||
cursor: pointer;
|
|
||||||
height: 24px;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
width: 100%;
|
|
||||||
background: rgba($white, 0.35);
|
|
||||||
border-radius: 4px;
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
height: 4px;
|
|
||||||
top: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__progress,
|
|
||||||
&__buffer {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
height: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
top: 14px;
|
|
||||||
background: lighten($ui-highlight-color, 8%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buffer {
|
|
||||||
background: rgba($white, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__handle {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 3;
|
|
||||||
opacity: 0;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
top: 10px;
|
|
||||||
margin-inline-start: -6px;
|
|
||||||
background: lighten($ui-highlight-color, 8%);
|
|
||||||
box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
|
|
||||||
|
|
||||||
.no-reduce-motion & {
|
|
||||||
transition: opacity 0.1s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.video-player__seek__handle {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.detailed,
|
|
||||||
&.fullscreen {
|
|
||||||
.video-player__buttons {
|
|
||||||
.player-button {
|
|
||||||
padding-top: 10px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.gifv {
|
|
||||||
video {
|
|
||||||
max-width: 100vw;
|
|
||||||
max-height: 80vh;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,209 +0,0 @@
|
||||||
.privacy-policy {
|
|
||||||
background: $ui-base-color;
|
|
||||||
padding: 20px;
|
|
||||||
|
|
||||||
@media screen and (min-width: $no-gap-breakpoint) {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__body {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose {
|
|
||||||
color: $secondary-text-color;
|
|
||||||
font-size: 15px;
|
|
||||||
line-height: 22px;
|
|
||||||
|
|
||||||
p,
|
|
||||||
ul,
|
|
||||||
ol {
|
|
||||||
margin-top: 1.25em;
|
|
||||||
margin-bottom: 1.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
margin-top: 2em;
|
|
||||||
margin-bottom: 2em;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
video {
|
|
||||||
margin-top: 2em;
|
|
||||||
margin-bottom: 2em;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin-top: 2em;
|
|
||||||
margin-bottom: 2em;
|
|
||||||
|
|
||||||
figcaption {
|
|
||||||
font-size: 0.875em;
|
|
||||||
line-height: 1.4285714;
|
|
||||||
margin-top: 0.8571429em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
figure > * {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 1.5em;
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
line-height: 1.33;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 1.25em;
|
|
||||||
margin-top: 1.6em;
|
|
||||||
margin-bottom: 0.6em;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6 {
|
|
||||||
margin-top: 1.5em;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol {
|
|
||||||
counter-reset: list-counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol > li {
|
|
||||||
counter-increment: list-counter;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: counter(list-counter) '.';
|
|
||||||
position: absolute;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul > li::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
background-color: $darker-text-color;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 0.375em;
|
|
||||||
height: 0.375em;
|
|
||||||
top: 0.5em;
|
|
||||||
inset-inline-start: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul > li,
|
|
||||||
ol > li {
|
|
||||||
position: relative;
|
|
||||||
padding-inline-start: 1.75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > ul > li p {
|
|
||||||
margin-top: 0.75em;
|
|
||||||
margin-bottom: 0.75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > ul > li > *:first-child {
|
|
||||||
margin-top: 1.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > ul > li > *:last-child {
|
|
||||||
margin-bottom: 1.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > ol > li > *:first-child {
|
|
||||||
margin-top: 1.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > ol > li > *:last-child {
|
|
||||||
margin-bottom: 1.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul ul,
|
|
||||||
ul ol,
|
|
||||||
ol ul,
|
|
||||||
ol ol {
|
|
||||||
margin-top: 0.75em;
|
|
||||||
margin-bottom: 0.75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6,
|
|
||||||
strong,
|
|
||||||
b {
|
|
||||||
color: $primary-text-color;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
em,
|
|
||||||
i {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: $highlight-text-color;
|
|
||||||
text-decoration: underline;
|
|
||||||
|
|
||||||
&:focus,
|
|
||||||
&:hover,
|
|
||||||
&:active {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-size: 0.875em;
|
|
||||||
background: darken($ui-base-color, 8%);
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 0.2em 0.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
border: 0;
|
|
||||||
border-top: 1px solid lighten($ui-base-color, 4%);
|
|
||||||
margin-top: 3em;
|
|
||||||
margin-bottom: 3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr + * {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 + * {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 + * {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 + *,
|
|
||||||
h5 + *,
|
|
||||||
h6 + * {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > :first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > :last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
.regeneration-indicator {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: $dark-text-color;
|
|
||||||
background: $ui-base-color;
|
|
||||||
cursor: default;
|
|
||||||
display: flex;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 20px;
|
|
||||||
|
|
||||||
&__figure {
|
|
||||||
&,
|
|
||||||
img {
|
|
||||||
display: block;
|
|
||||||
width: auto;
|
|
||||||
height: 160px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--without-header {
|
|
||||||
padding-top: 20px + 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__label {
|
|
||||||
margin-top: 30px;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
color: $dark-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,329 +0,0 @@
|
||||||
.search {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&__popout {
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
margin-top: -2px;
|
|
||||||
width: 100%;
|
|
||||||
background: $ui-base-color;
|
|
||||||
border-radius: 0 0 4px 4px;
|
|
||||||
box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);
|
|
||||||
z-index: 99;
|
|
||||||
font-size: 13px;
|
|
||||||
padding: 15px 5px;
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: $dark-text-color;
|
|
||||||
font-weight: 500;
|
|
||||||
padding: 0 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__menu {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__message {
|
|
||||||
color: $dark-text-color;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item {
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%;
|
|
||||||
border: 0;
|
|
||||||
font: inherit;
|
|
||||||
background: transparent;
|
|
||||||
color: $darker-text-color;
|
|
||||||
padding: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 4px;
|
|
||||||
text-align: start;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
&--flex {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active,
|
|
||||||
&.selected {
|
|
||||||
background: $ui-highlight-color;
|
|
||||||
color: $primary-text-color;
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
color: $primary-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mark {
|
|
||||||
background: transparent;
|
|
||||||
font-weight: 700;
|
|
||||||
color: $primary-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
overflow: inherit;
|
|
||||||
text-overflow: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
.search__popout {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search__input {
|
|
||||||
@include search-input;
|
|
||||||
|
|
||||||
display: block;
|
|
||||||
padding: 15px;
|
|
||||||
padding-inline-end: 30px;
|
|
||||||
line-height: 18px;
|
|
||||||
font-size: 16px;
|
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
color: lighten($darker-text-color, 4%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-moz-focus-inner {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-moz-focus-inner,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
outline: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
background: lighten($ui-base-color, 4%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search__icon {
|
|
||||||
&::-moz-focus-inner {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-moz-focus-inner,
|
|
||||||
&:focus {
|
|
||||||
outline: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
position: absolute;
|
|
||||||
top: 13px;
|
|
||||||
inset-inline-end: 10px;
|
|
||||||
display: inline-block;
|
|
||||||
opacity: 0;
|
|
||||||
transition: all 100ms linear;
|
|
||||||
transition-property: color, transform, opacity;
|
|
||||||
font-size: 18px;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
color: $secondary-text-color;
|
|
||||||
cursor: default;
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
pointer-events: auto;
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-search {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
pointer-events: auto;
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-times-circle {
|
|
||||||
top: 17px;
|
|
||||||
transform: rotate(0deg);
|
|
||||||
color: $action-button-color;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: lighten($action-button-color, 7%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-results__header {
|
|
||||||
color: $dark-text-color;
|
|
||||||
background: lighten($ui-base-color, 2%);
|
|
||||||
padding: 15px;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 16px;
|
|
||||||
cursor: default;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-results__info {
|
|
||||||
padding: 20px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trends {
|
|
||||||
&__item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 15px;
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
gap: 15px;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__name {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
color: $dark-text-color;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: $darker-text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
span {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__current {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-align: end;
|
|
||||||
color: $secondary-text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__sparkline {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
width: 50px;
|
|
||||||
|
|
||||||
path:first-child {
|
|
||||||
fill: rgba($highlight-text-color, 0.25) !important;
|
|
||||||
fill-opacity: 1 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
path:last-child {
|
|
||||||
stroke: lighten($highlight-text-color, 6%) !important;
|
|
||||||
fill: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--requires-review {
|
|
||||||
.trends__item__name {
|
|
||||||
color: $gold-star;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: $gold-star;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.trends__item__current {
|
|
||||||
color: $gold-star;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trends__item__sparkline {
|
|
||||||
path:first-child {
|
|
||||||
fill: rgba($gold-star, 0.25) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
path:last-child {
|
|
||||||
stroke: lighten($gold-star, 6%) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--disabled {
|
|
||||||
.trends__item__name {
|
|
||||||
color: lighten($ui-base-color, 12%);
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: lighten($ui-base-color, 12%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.trends__item__current {
|
|
||||||
color: lighten($ui-base-color, 12%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.trends__item__sparkline {
|
|
||||||
path:first-child {
|
|
||||||
fill: rgba(lighten($ui-base-color, 12%), 0.25) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
path:last-child {
|
|
||||||
stroke: lighten(lighten($ui-base-color, 12%), 6%) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--compact &__item {
|
|
||||||
padding: 10px;
|
|
||||||
padding-inline-end: 28px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
.sensitive-info {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
position: absolute;
|
|
||||||
top: 4px;
|
|
||||||
inset-inline-start: 4px;
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sensitive-marker {
|
|
||||||
margin: 0 3px;
|
|
||||||
border-radius: 2px;
|
|
||||||
padding: 2px 6px;
|
|
||||||
color: rgba($primary-text-color, 0.8);
|
|
||||||
background: rgba($base-overlay-background, 0.5);
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 18px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
opacity: 0.9;
|
|
||||||
transition: opacity 0.1s ease;
|
|
||||||
|
|
||||||
.media-gallery:hover & {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
.sign-in-banner {
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
p {
|
|
||||||
color: $darker-text-color;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: $secondary-text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
unicode-bidi: isolate;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.server-banner {
|
|
||||||
padding: 20px 0;
|
|
||||||
|
|
||||||
&__introduction {
|
|
||||||
color: $darker-text-color;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: underline;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__hero {
|
|
||||||
display: block;
|
|
||||||
border-radius: 4px;
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
aspect-ratio: 1.9;
|
|
||||||
border: 0;
|
|
||||||
background: $ui-base-color;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__description {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__meta {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
max-width: 100%;
|
|
||||||
|
|
||||||
&__column {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
width: calc(50% - 5px);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__number {
|
|
||||||
font-weight: 600;
|
|
||||||
color: $primary-text-color;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__number-label {
|
|
||||||
color: $darker-text-color;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: $darker-text-color;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account {
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__avatar-wrapper {
|
|
||||||
margin-inline-start: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spacer {
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,319 +0,0 @@
|
||||||
.compose-panel {
|
|
||||||
width: 285px;
|
|
||||||
margin-top: 10px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: calc(100% - 10px);
|
|
||||||
overflow-y: hidden;
|
|
||||||
|
|
||||||
.hero-widget {
|
|
||||||
box-shadow: none;
|
|
||||||
|
|
||||||
&__text,
|
|
||||||
&__img,
|
|
||||||
&__img img {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__text {
|
|
||||||
padding: 15px;
|
|
||||||
color: $secondary-text-color;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 700;
|
|
||||||
color: $primary-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search__input {
|
|
||||||
line-height: 18px;
|
|
||||||
font-size: 16px;
|
|
||||||
padding: 15px;
|
|
||||||
padding-inline-end: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search__icon .fa {
|
|
||||||
top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navigation-bar {
|
|
||||||
flex: 0 1 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
min-height: 310px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__autosuggest-wrapper {
|
|
||||||
overflow-y: auto;
|
|
||||||
background-color: $white;
|
|
||||||
border-radius: 4px 4px 0 0;
|
|
||||||
flex: 0 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-textarea__textarea {
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.navigation-panel {
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
height: calc(100% - 20px);
|
|
||||||
overflow-y: auto;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
& > a {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
height: 30px;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.navigation-panel,
|
|
||||||
.compose-panel {
|
|
||||||
hr {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
border: 0;
|
|
||||||
background: transparent;
|
|
||||||
border-top: 1px solid lighten($ui-base-color, 4%);
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-spacer {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.columns-area--mobile {
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
.column,
|
|
||||||
.drawer {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-card {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-form {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-textarea__textarea {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search__input {
|
|
||||||
line-height: 18px;
|
|
||||||
font-size: 16px;
|
|
||||||
padding: 15px;
|
|
||||||
padding-inline-end: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search__icon .fa {
|
|
||||||
top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrollable {
|
|
||||||
overflow: visible;
|
|
||||||
|
|
||||||
@supports (display: grid) {
|
|
||||||
contain: content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: $no-gap-breakpoint) {
|
|
||||||
padding: 10px 0;
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailed-status {
|
|
||||||
padding: 15px;
|
|
||||||
|
|
||||||
.media-gallery,
|
|
||||||
.video-player,
|
|
||||||
.audio-player {
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__header__bar {
|
|
||||||
padding: 5px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navigation-bar,
|
|
||||||
.compose-form {
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form .compose-form__publish .compose-form__publish-button-wrapper {
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification__report {
|
|
||||||
padding: 15px;
|
|
||||||
padding-inline-start: (48px + 15px * 2);
|
|
||||||
min-height: 48px + 2px;
|
|
||||||
|
|
||||||
&__avatar {
|
|
||||||
inset-inline-start: 15px;
|
|
||||||
top: 17px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
padding: 15px;
|
|
||||||
min-height: 48px + 2px;
|
|
||||||
|
|
||||||
.media-gallery,
|
|
||||||
&__action-bar,
|
|
||||||
.video-player,
|
|
||||||
.audio-player {
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account {
|
|
||||||
padding: 15px 10px;
|
|
||||||
|
|
||||||
&__header__bio {
|
|
||||||
margin: 0 -10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification {
|
|
||||||
&__message {
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
padding-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account {
|
|
||||||
padding-top: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: $no-gap-breakpoint) {
|
|
||||||
.react-swipeable-view-container .columns-area--mobile {
|
|
||||||
height: calc(100% - 10px) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.getting-started__wrapper {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-page .search {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navigation-panel__legal {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: $no-gap-breakpoint - 1px) {
|
|
||||||
$sidebar-width: 285px;
|
|
||||||
|
|
||||||
.columns-area__panels__main {
|
|
||||||
width: calc(100% - $sidebar-width);
|
|
||||||
}
|
|
||||||
|
|
||||||
.columns-area__panels {
|
|
||||||
min-height: calc(100vh - $ui-header-height);
|
|
||||||
}
|
|
||||||
|
|
||||||
.columns-area__panels__pane--navigational {
|
|
||||||
min-width: $sidebar-width;
|
|
||||||
|
|
||||||
.columns-area__panels__pane__inner {
|
|
||||||
width: $sidebar-width;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navigation-panel {
|
|
||||||
margin: 0;
|
|
||||||
background: $ui-base-color;
|
|
||||||
border-inline-start: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navigation-panel__sign-in-banner,
|
|
||||||
.navigation-panel__logo,
|
|
||||||
.navigation-panel__banner,
|
|
||||||
.getting-started__trends {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.column-link__icon {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.layout-single-column .ui__header {
|
|
||||||
display: flex;
|
|
||||||
background: $ui-base-color;
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.column-header,
|
|
||||||
.column-back-button,
|
|
||||||
.scrollable,
|
|
||||||
.error-column {
|
|
||||||
border-radius: 0 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: $no-gap-breakpoint - 285px - 1px) {
|
|
||||||
$sidebar-width: 55px;
|
|
||||||
|
|
||||||
.columns-area__panels__main {
|
|
||||||
width: calc(100% - $sidebar-width);
|
|
||||||
}
|
|
||||||
|
|
||||||
.columns-area__panels__pane--navigational {
|
|
||||||
min-width: $sidebar-width;
|
|
||||||
|
|
||||||
.columns-area__panels__pane__inner {
|
|
||||||
width: $sidebar-width;
|
|
||||||
}
|
|
||||||
|
|
||||||
.column-link span {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-panel {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.explore__search-header {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: $no-gap-breakpoint - 1px) {
|
|
||||||
.columns-area__panels__pane--compositional {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.explore__search-header {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +1,14 @@
|
||||||
.emoji-mart {
|
.emoji-mart {
|
||||||
|
font-size: 13px;
|
||||||
|
display: inline-block;
|
||||||
|
color: $inverted-text-color;
|
||||||
|
|
||||||
&,
|
&,
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
line-height: 1.15;
|
line-height: 1.15;
|
||||||
}
|
}
|
||||||
|
|
||||||
font-size: 13px;
|
|
||||||
display: inline-block;
|
|
||||||
color: $inverted-text-color;
|
|
||||||
|
|
||||||
.emoji-mart-emoji {
|
.emoji-mart-emoji {
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
@ -64,17 +64,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.emoji-mart-anchor-bar {
|
.emoji-mart-anchor-bar {
|
||||||
bottom: 0;
|
bottom: -1px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.emoji-mart-anchor-bar {
|
.emoji-mart-anchor-bar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -3px;
|
bottom: -5px;
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 3px;
|
height: 4px;
|
||||||
background-color: darken($ui-highlight-color, 3%);
|
background-color: $highlight-text-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emoji-mart-anchors {
|
.emoji-mart-anchors {
|
||||||
|
@ -173,7 +173,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover::before {
|
&:hover::before {
|
||||||
z-index: 0;
|
z-index: -1;
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
|
@ -13,8 +13,9 @@
|
||||||
@import 'forms';
|
@import 'forms';
|
||||||
@import 'accounts';
|
@import 'accounts';
|
||||||
@import 'statuses';
|
@import 'statuses';
|
||||||
@import 'components/index';
|
@import 'components';
|
||||||
@import 'polls';
|
@import 'polls';
|
||||||
|
@import 'emoji_picker';
|
||||||
@import 'about';
|
@import 'about';
|
||||||
@import 'tables';
|
@import 'tables';
|
||||||
@import 'admin';
|
@import 'admin';
|
||||||
|
@ -22,3 +23,5 @@
|
||||||
@import 'rtl';
|
@import 'rtl';
|
||||||
@import 'dashboard';
|
@import 'dashboard';
|
||||||
@import 'rich_text';
|
@import 'rich_text';
|
||||||
|
@import 'glitch_local_settings';
|
||||||
|
@import 'glitch_doodle';
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
.status__content__text,
|
.status__content__text,
|
||||||
.e-content,
|
.e-content,
|
||||||
|
.quote-indicator__content,
|
||||||
.reply-indicator__content {
|
.reply-indicator__content {
|
||||||
pre,
|
pre,
|
||||||
blockquote {
|
blockquote {
|
||||||
|
@ -91,6 +92,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quote-indicator__content,
|
||||||
.reply-indicator__content {
|
.reply-indicator__content {
|
||||||
blockquote {
|
blockquote {
|
||||||
border-inline-start-color: $inverted-text-color;
|
border-inline-start-color: $inverted-text-color;
|
||||||
|
|
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.4 KiB |
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M800-680v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80ZM620-520q25 0 42.5-17.5T680-580q0-25-17.5-42.5T620-640q-25 0-42.5 17.5T560-580q0 25 17.5 42.5T620-520Zm-280 0q25 0 42.5-17.5T400-580q0-25-17.5-42.5T340-640q-25 0-42.5 17.5T280-580q0 25 17.5 42.5T340-520Zm140 260q68 0 123.5-38.5T684-400H276q25 63 80.5 101.5T480-260Zm0 180q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q43 0 83 8.5t77 24.5v167h80v80h142q9 29 13.5 58.5T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Z"/></svg>
|
|
Before Width: | Height: | Size: 622 B |
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-480Zm0 400q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q43 0 83 8.5t77 24.5v90q-35-20-75.5-31.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160q133 0 226.5-93.5T800-480q0-32-6.5-62T776-600h86q9 29 13.5 58.5T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm320-600v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80ZM620-520q25 0 42.5-17.5T680-580q0-25-17.5-42.5T620-640q-25 0-42.5 17.5T560-580q0 25 17.5 42.5T620-520Zm-280 0q25 0 42.5-17.5T400-580q0-25-17.5-42.5T340-640q-25 0-42.5 17.5T280-580q0 25 17.5 42.5T340-520Zm140 260q68 0 123.5-38.5T684-400H276q25 63 80.5 101.5T480-260Z"/></svg>
|
|
Before Width: | Height: | Size: 744 B |
1
app/javascript/material-icons/400-24px/colors-fill.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M346-140 100-386q-10-10-15-22t-5-25q0-13 5-25t15-22l230-229-106-106 62-65 400 400q10 10 14.5 22t4.5 25q0 13-4.5 25T686-386L440-140q-10 10-22 15t-25 5q-13 0-25-5t-22-15Zm47-506L179-432h428L393-646Zm399 526q-36 0-61-25.5T706-208q0-27 13.5-51t30.5-47l42-54 44 54q16 23 30 47t14 51q0 37-26 62.5T792-120Z"/></svg>
|
After Width: | Height: | Size: 405 B |
1
app/javascript/material-icons/400-24px/colors.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M346-140 100-386q-10-10-15-22t-5-25q0-13 5-25t15-22l230-229-106-106 62-65 400 400q10 10 14.5 22t4.5 25q0 13-4.5 25T686-386L440-140q-10 10-22 15t-25 5q-13 0-25-5t-22-15Zm47-506L179-432h428L393-646Zm399 526q-36 0-61-25.5T706-208q0-27 13.5-51t30.5-47l42-54 44 54q16 23 30 47t14 51q0 37-26 62.5T792-120Z"/></svg>
|
After Width: | Height: | Size: 405 B |
1
app/javascript/material-icons/400-24px/undo-fill.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M280-200v-80h284q63 0 109.5-40T720-420q0-60-46.5-100T564-560H312l104 104-56 56-200-200 200-200 56 56-104 104h252q97 0 166.5 63T800-420q0 94-69.5 157T564-200H280Z"/></svg>
|
After Width: | Height: | Size: 267 B |
1
app/javascript/material-icons/400-24px/undo.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M280-200v-80h284q63 0 109.5-40T720-420q0-60-46.5-100T564-560H312l104 104-56 56-200-200 200-200 56 56-104 104h252q97 0 166.5 63T800-420q0 94-69.5 157T564-200H280Z"/></svg>
|
After Width: | Height: | Size: 267 B |
|
@ -39,8 +39,6 @@ class ActivityPub::Activity
|
||||||
ActivityPub::Activity::Follow
|
ActivityPub::Activity::Follow
|
||||||
when 'Like'
|
when 'Like'
|
||||||
ActivityPub::Activity::Like
|
ActivityPub::Activity::Like
|
||||||
when 'EmojiReact'
|
|
||||||
ActivityPub::Activity::EmojiReact
|
|
||||||
when 'Block'
|
when 'Block'
|
||||||
ActivityPub::Activity::Block
|
ActivityPub::Activity::Block
|
||||||
when 'Update'
|
when 'Update'
|
||||||
|
@ -178,32 +176,4 @@ class ActivityPub::Activity
|
||||||
Rails.logger.info("Rejected #{@json['type']} activity #{@json['id']} from #{@account.uri}#{@options[:relayed_through_actor] && "via #{@options[:relayed_through_actor].uri}"}")
|
Rails.logger.info("Rejected #{@json['type']} activity #{@json['id']} from #{@account.uri}#{@options[:relayed_through_actor] && "via #{@options[:relayed_through_actor].uri}"}")
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# Ensure emoji declared in the activity's tags are
|
|
||||||
# present in the database and downloaded to the local cache.
|
|
||||||
# Required by EmojiReact and Like for emoji reactions.
|
|
||||||
def process_emoji_tags(name, tags)
|
|
||||||
tag = as_array(tags).find { |item| item['type'] == 'Emoji' }
|
|
||||||
return if tag.nil?
|
|
||||||
|
|
||||||
custom_emoji_parser = ActivityPub::Parser::CustomEmojiParser.new(tag)
|
|
||||||
return if custom_emoji_parser.shortcode.blank? || custom_emoji_parser.image_remote_url.blank? || !name.eql?(custom_emoji_parser.shortcode)
|
|
||||||
|
|
||||||
emoji = CustomEmoji.find_by(shortcode: custom_emoji_parser.shortcode, domain: @account.domain)
|
|
||||||
return emoji unless emoji.nil? ||
|
|
||||||
custom_emoji_parser.image_remote_url != emoji.image_remote_url ||
|
|
||||||
(custom_emoji_parser.updated_at && custom_emoji_parser.updated_at >= emoji.updated_at)
|
|
||||||
|
|
||||||
begin
|
|
||||||
emoji ||= CustomEmoji.new(domain: @account.domain,
|
|
||||||
shortcode: custom_emoji_parser.shortcode,
|
|
||||||
uri: custom_emoji_parser.uri)
|
|
||||||
emoji.image_remote_url = custom_emoji_parser.image_remote_url
|
|
||||||
emoji.save
|
|
||||||
rescue Seahorse::Client::NetworkingError => e
|
|
||||||
Rails.logger.warn "Error fetching emoji: #{e}"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
emoji
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class ActivityPub::Activity::EmojiReact < ActivityPub::Activity
|
|
||||||
def perform
|
|
||||||
original_status = status_from_uri(object_uri)
|
|
||||||
name = @json['content']
|
|
||||||
return if original_status.nil? ||
|
|
||||||
!original_status.account.local? ||
|
|
||||||
delete_arrived_first?(@json['id'])
|
|
||||||
|
|
||||||
if /^:.*:$/.match?(name)
|
|
||||||
name.delete! ':'
|
|
||||||
custom_emoji = process_emoji_tags(name, @json['tag'])
|
|
||||||
|
|
||||||
return if custom_emoji.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
return if @account.reacted?(original_status, name, custom_emoji)
|
|
||||||
|
|
||||||
reaction = original_status.status_reactions.create!(account: @account, name: name, custom_emoji: custom_emoji)
|
|
||||||
|
|
||||||
LocalNotificationWorker.perform_async(original_status.account_id, reaction.id, 'StatusReaction', 'reaction')
|
|
||||||
rescue ActiveRecord::RecordInvalid
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -3,39 +3,12 @@
|
||||||
class ActivityPub::Activity::Like < ActivityPub::Activity
|
class ActivityPub::Activity::Like < ActivityPub::Activity
|
||||||
def perform
|
def perform
|
||||||
original_status = status_from_uri(object_uri)
|
original_status = status_from_uri(object_uri)
|
||||||
return if original_status.nil? || !original_status.account.local? || delete_arrived_first?(@json['id'])
|
|
||||||
|
|
||||||
return if maybe_process_embedded_reaction
|
return if original_status.nil? || !original_status.account.local? || delete_arrived_first?(@json['id']) || @account.favourited?(original_status)
|
||||||
|
|
||||||
return if @account.favourited?(original_status)
|
|
||||||
|
|
||||||
favourite = original_status.favourites.create!(account: @account)
|
favourite = original_status.favourites.create!(account: @account)
|
||||||
|
|
||||||
LocalNotificationWorker.perform_async(original_status.account_id, favourite.id, 'Favourite', 'favourite')
|
LocalNotificationWorker.perform_async(original_status.account_id, favourite.id, 'Favourite', 'favourite')
|
||||||
Trends.statuses.register(original_status)
|
Trends.statuses.register(original_status)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Some servers deliver reactions as likes with the emoji in content
|
|
||||||
# Versions of Misskey before 12.1.0 specify emojis in _misskey_reaction instead, so we check both
|
|
||||||
# See https://misskey-hub.net/ns.html#misskey-reaction for details
|
|
||||||
def maybe_process_embedded_reaction
|
|
||||||
original_status = status_from_uri(object_uri)
|
|
||||||
name = @json['content'] || @json['_misskey_reaction']
|
|
||||||
return false if name.nil?
|
|
||||||
|
|
||||||
if /^:.*:$/.match?(name)
|
|
||||||
name.delete! ':'
|
|
||||||
custom_emoji = process_emoji_tags(name, @json['tag'])
|
|
||||||
|
|
||||||
return false if custom_emoji.nil? # invalid custom emoji, treat it as a regular like
|
|
||||||
end
|
|
||||||
return true if @account.reacted?(original_status, name, custom_emoji)
|
|
||||||
|
|
||||||
reaction = original_status.status_reactions.create!(account: @account, name: name, custom_emoji: custom_emoji)
|
|
||||||
LocalNotificationWorker.perform_async(original_status.account_id, reaction.id, 'StatusReaction', 'reaction')
|
|
||||||
true
|
|
||||||
# account tried to react with disabled custom emoji. Returning true to discard activity.
|
|
||||||
rescue ActiveRecord::RecordInvalid
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,8 +11,6 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity
|
||||||
undo_follow
|
undo_follow
|
||||||
when 'Like'
|
when 'Like'
|
||||||
undo_like
|
undo_like
|
||||||
when 'EmojiReact'
|
|
||||||
undo_emoji_react
|
|
||||||
when 'Block'
|
when 'Block'
|
||||||
undo_block
|
undo_block
|
||||||
when nil
|
when nil
|
||||||
|
@ -110,31 +108,6 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity
|
||||||
if @account.favourited?(status)
|
if @account.favourited?(status)
|
||||||
favourite = status.favourites.where(account: @account).first
|
favourite = status.favourites.where(account: @account).first
|
||||||
favourite&.destroy
|
favourite&.destroy
|
||||||
elsif @object['content'].present? || @object['_misskey_reaction'].present?
|
|
||||||
undo_emoji_react
|
|
||||||
else
|
|
||||||
delete_later!(object_uri)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def undo_emoji_react
|
|
||||||
name = @object['content'] || @object['_misskey_reaction']
|
|
||||||
return if name.nil?
|
|
||||||
|
|
||||||
status = status_from_uri(target_uri)
|
|
||||||
|
|
||||||
return if status.nil? || !status.account.local?
|
|
||||||
|
|
||||||
if /^:.*:$/.match?(name)
|
|
||||||
name.delete! ':'
|
|
||||||
custom_emoji = process_emoji_tags(name, @object['tag'])
|
|
||||||
|
|
||||||
return if custom_emoji.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
if @account.reacted?(status, name, custom_emoji)
|
|
||||||
reaction = status.status_reactions.where(account: @account, name: name).first
|
|
||||||
reaction&.destroy
|
|
||||||
else
|
else
|
||||||
delete_later!(object_uri)
|
delete_later!(object_uri)
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,14 +4,34 @@ module ApplicationExtension
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
included do
|
included do
|
||||||
|
include Redisable
|
||||||
|
|
||||||
has_many :created_users, class_name: 'User', foreign_key: 'created_by_application_id', inverse_of: :created_by_application
|
has_many :created_users, class_name: 'User', foreign_key: 'created_by_application_id', inverse_of: :created_by_application
|
||||||
|
|
||||||
validates :name, length: { maximum: 60 }
|
validates :name, length: { maximum: 60 }
|
||||||
validates :website, url: true, length: { maximum: 2_000 }, if: :website?
|
validates :website, url: true, length: { maximum: 2_000 }, if: :website?
|
||||||
validates :redirect_uri, length: { maximum: 2_000 }
|
validates :redirect_uri, length: { maximum: 2_000 }
|
||||||
|
|
||||||
|
# The relationship used between Applications and AccessTokens is using
|
||||||
|
# dependent: delete_all, which means the ActiveRecord callback in
|
||||||
|
# AccessTokenExtension is not run, so instead we manually announce to
|
||||||
|
# streaming that these tokens are being deleted.
|
||||||
|
before_destroy :push_to_streaming_api, prepend: true
|
||||||
end
|
end
|
||||||
|
|
||||||
def confirmation_redirect_uri
|
def confirmation_redirect_uri
|
||||||
redirect_uri.lines.first.strip
|
redirect_uri.lines.first.strip
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def push_to_streaming_api
|
||||||
|
# TODO: #28793 Combine into a single topic
|
||||||
|
payload = Oj.dump(event: :kill)
|
||||||
|
access_tokens.in_batches do |tokens|
|
||||||
|
redis.pipelined do |pipeline|
|
||||||
|
tokens.ids.each do |id|
|
||||||
|
pipeline.publish("timeline:access_token:#{id}", payload)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,8 +6,8 @@ class NotificationMailer < ApplicationMailer
|
||||||
:routing
|
:routing
|
||||||
|
|
||||||
before_action :process_params
|
before_action :process_params
|
||||||
before_action :set_status, only: [:mention, :favourite, :reaction, :reblog]
|
before_action :set_status, only: [:mention, :favourite, :reblog]
|
||||||
before_action :set_account, only: [:follow, :favourite, :reaction, :reblog, :follow_request]
|
before_action :set_account, only: [:follow, :favourite, :reblog, :follow_request]
|
||||||
after_action :set_list_headers!
|
after_action :set_list_headers!
|
||||||
|
|
||||||
default to: -> { email_address_with_name(@user.email, @me.username) }
|
default to: -> { email_address_with_name(@user.email, @me.username) }
|
||||||
|
@ -40,15 +40,6 @@ class NotificationMailer < ApplicationMailer
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def reaction
|
|
||||||
return unless @user.functional? && @status.present?
|
|
||||||
|
|
||||||
locale_for_account(@me) do
|
|
||||||
thread_by_conversation(@status.conversation)
|
|
||||||
mail subject: default_i18n_subject(name: @account.acct)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def reblog
|
def reblog
|
||||||
return unless @user.functional? && @status.present?
|
return unless @user.functional? && @status.present?
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ module Account::Associations
|
||||||
# Timelines
|
# Timelines
|
||||||
has_many :statuses, inverse_of: :account, dependent: :destroy
|
has_many :statuses, inverse_of: :account, dependent: :destroy
|
||||||
has_many :favourites, inverse_of: :account, dependent: :destroy
|
has_many :favourites, inverse_of: :account, dependent: :destroy
|
||||||
has_many :status_reactions, inverse_of: :account, dependent: :destroy
|
|
||||||
has_many :bookmarks, inverse_of: :account, dependent: :destroy
|
has_many :bookmarks, inverse_of: :account, dependent: :destroy
|
||||||
has_many :mentions, inverse_of: :account, dependent: :destroy
|
has_many :mentions, inverse_of: :account, dependent: :destroy
|
||||||
has_many :notifications, inverse_of: :account, dependent: :destroy
|
has_many :notifications, inverse_of: :account, dependent: :destroy
|
||||||
|
|
|
@ -230,10 +230,6 @@ module Account::Interactions
|
||||||
status.proper.favourites.exists?(account: self)
|
status.proper.favourites.exists?(account: self)
|
||||||
end
|
end
|
||||||
|
|
||||||
def reacted?(status, name, custom_emoji = nil)
|
|
||||||
status.proper.status_reactions.exists?(account: self, name: name, custom_emoji: custom_emoji)
|
|
||||||
end
|
|
||||||
|
|
||||||
def bookmarked?(status)
|
def bookmarked?(status)
|
||||||
status.proper.bookmarks.exists?(account: self)
|
status.proper.bookmarks.exists?(account: self)
|
||||||
end
|
end
|
||||||
|
|
|
@ -123,10 +123,6 @@ module User::HasSettings
|
||||||
settings['hide_followers_count']
|
settings['hide_followers_count']
|
||||||
end
|
end
|
||||||
|
|
||||||
def setting_visible_reactions
|
|
||||||
integer_cast_setting('visible_reactions', 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
def allows_report_emails?
|
def allows_report_emails?
|
||||||
settings['notification_emails.report']
|
settings['notification_emails.report']
|
||||||
end
|
end
|
||||||
|
@ -170,14 +166,4 @@ module User::HasSettings
|
||||||
def hide_all_media?
|
def hide_all_media?
|
||||||
settings['web.display_media'] == 'hide_all'
|
settings['web.display_media'] == 'hide_all'
|
||||||
end
|
end
|
||||||
|
|
||||||
def integer_cast_setting(key, min = nil, max = nil)
|
|
||||||
i = ActiveModel::Type::Integer.new.cast(settings[key])
|
|
||||||
# the cast above doesn't return a number if passed the string "e"
|
|
||||||
i = 0 unless i.is_a? Numeric
|
|
||||||
return min if !min.nil? && i < min
|
|
||||||
return max if !max.nil? && i > max
|
|
||||||
|
|
||||||
i
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,7 +25,15 @@ module User::LdapAuthenticable
|
||||||
resource = joins(:account).find_by(accounts: { username: safe_username })
|
resource = joins(:account).find_by(accounts: { username: safe_username })
|
||||||
|
|
||||||
if resource.blank?
|
if resource.blank?
|
||||||
resource = new(email: attributes[Devise.ldap_mail.to_sym].first, agreement: true, account_attributes: { username: safe_username }, admin: false, external: true, confirmed_at: Time.now.utc)
|
resource = new(
|
||||||
|
email: attributes[Devise.ldap_mail.to_sym].first,
|
||||||
|
agreement: true,
|
||||||
|
account_attributes: {
|
||||||
|
username: safe_username,
|
||||||
|
},
|
||||||
|
external: true,
|
||||||
|
confirmed_at: Time.now.utc
|
||||||
|
)
|
||||||
resource.save!
|
resource.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -19,17 +19,18 @@ module User::Omniauthable
|
||||||
end
|
end
|
||||||
|
|
||||||
class_methods do
|
class_methods do
|
||||||
def find_for_oauth(auth, signed_in_resource = nil)
|
def find_for_omniauth(auth, signed_in_resource = nil)
|
||||||
# EOLE-SSO Patch
|
# EOLE-SSO Patch
|
||||||
auth.uid = (auth.uid[0][:uid] || auth.uid[0][:user]) if auth.uid.is_a? Hashie::Array
|
auth.uid = (auth.uid[0][:uid] || auth.uid[0][:user]) if auth.uid.is_a? Hashie::Array
|
||||||
identity = Identity.find_for_oauth(auth)
|
identity = Identity.find_for_omniauth(auth)
|
||||||
|
|
||||||
# If a signed_in_resource is provided it always overrides the existing user
|
# If a signed_in_resource is provided it always overrides the existing user
|
||||||
# to prevent the identity being locked with accidentally created accounts.
|
# to prevent the identity being locked with accidentally created accounts.
|
||||||
# Note that this may leave zombie accounts (with no associated identity) which
|
# Note that this may leave zombie accounts (with no associated identity) which
|
||||||
# can be cleaned up at a later date.
|
# can be cleaned up at a later date.
|
||||||
user = signed_in_resource || identity.user
|
user = signed_in_resource || identity.user
|
||||||
user ||= create_for_oauth(auth)
|
user ||= reattach_for_auth(auth)
|
||||||
|
user ||= create_for_auth(auth)
|
||||||
|
|
||||||
if identity.user.nil?
|
if identity.user.nil?
|
||||||
identity.user = user
|
identity.user = user
|
||||||
|
@ -39,19 +40,35 @@ module User::Omniauthable
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_for_oauth(auth)
|
private
|
||||||
# Check if the user exists with provided email. If no email was provided,
|
|
||||||
|
def reattach_for_auth(auth)
|
||||||
|
# If allowed, check if a user exists with the provided email address,
|
||||||
|
# and return it if they does not have an associated identity with the
|
||||||
|
# current authentication provider.
|
||||||
|
|
||||||
|
# This can be used to provide a choice of alternative auth providers
|
||||||
|
# or provide smooth gradual transition between multiple auth providers,
|
||||||
|
# but this is discouraged because any insecure provider will put *all*
|
||||||
|
# local users at risk, regardless of which provider they registered with.
|
||||||
|
|
||||||
|
return unless ENV['ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH'] == 'true'
|
||||||
|
|
||||||
|
email, email_is_verified = email_from_auth(auth)
|
||||||
|
return unless email_is_verified
|
||||||
|
|
||||||
|
user = User.find_by(email: email)
|
||||||
|
return if user.nil? || Identity.exists?(provider: auth.provider, user_id: user.id)
|
||||||
|
|
||||||
|
user
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_for_auth(auth)
|
||||||
|
# Create a user for the given auth params. If no email was provided,
|
||||||
# we assign a temporary email and ask the user to verify it on
|
# we assign a temporary email and ask the user to verify it on
|
||||||
# the next step via Auth::SetupController.show
|
# the next step via Auth::SetupController.show
|
||||||
|
|
||||||
strategy = Devise.omniauth_configs[auth.provider.to_sym].strategy
|
email, email_is_verified = email_from_auth(auth)
|
||||||
assume_verified = strategy&.security&.assume_email_is_verified
|
|
||||||
email_is_verified = auth.info.verified || auth.info.verified_email || auth.info.email_verified || assume_verified
|
|
||||||
email = auth.info.verified_email || auth.info.email
|
|
||||||
|
|
||||||
user = User.find_by(email: email) if email_is_verified
|
|
||||||
|
|
||||||
return user unless user.nil?
|
|
||||||
|
|
||||||
user = User.new(user_params_from_auth(email, auth))
|
user = User.new(user_params_from_auth(email, auth))
|
||||||
|
|
||||||
|
@ -66,7 +83,14 @@ module User::Omniauthable
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def email_from_auth(auth)
|
||||||
|
strategy = Devise.omniauth_configs[auth.provider.to_sym].strategy
|
||||||
|
assume_verified = strategy&.security&.assume_email_is_verified
|
||||||
|
email_is_verified = auth.info.verified || auth.info.verified_email || auth.info.email_verified || assume_verified
|
||||||
|
email = auth.info.verified_email || auth.info.email
|
||||||
|
|
||||||
|
[email, email_is_verified]
|
||||||
|
end
|
||||||
|
|
||||||
def user_params_from_auth(email, auth)
|
def user_params_from_auth(email, auth)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,7 +32,6 @@ module User::PamAuthenticable
|
||||||
|
|
||||||
self.email = "#{account.username}@#{find_pam_suffix}" if email.nil? && find_pam_suffix
|
self.email = "#{account.username}@#{find_pam_suffix}" if email.nil? && find_pam_suffix
|
||||||
self.confirmed_at = Time.now.utc
|
self.confirmed_at = Time.now.utc
|
||||||
self.admin = false
|
|
||||||
self.account = account
|
self.account = account
|
||||||
self.external = true
|
self.external = true
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ class Identity < ApplicationRecord
|
||||||
validates :uid, presence: true, uniqueness: { scope: :provider }
|
validates :uid, presence: true, uniqueness: { scope: :provider }
|
||||||
validates :provider, presence: true
|
validates :provider, presence: true
|
||||||
|
|
||||||
def self.find_for_oauth(auth)
|
def self.find_for_omniauth(auth)
|
||||||
find_or_create_by(uid: auth.uid, provider: auth.provider)
|
find_or_create_by(uid: auth.uid, provider: auth.provider)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,7 +25,6 @@ class Notification < ApplicationRecord
|
||||||
'Follow' => :follow,
|
'Follow' => :follow,
|
||||||
'FollowRequest' => :follow_request,
|
'FollowRequest' => :follow_request,
|
||||||
'Favourite' => :favourite,
|
'Favourite' => :favourite,
|
||||||
'StatusReaction' => :reaction,
|
|
||||||
'Poll' => :poll,
|
'Poll' => :poll,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
@ -36,7 +35,6 @@ class Notification < ApplicationRecord
|
||||||
follow
|
follow
|
||||||
follow_request
|
follow_request
|
||||||
favourite
|
favourite
|
||||||
reaction
|
|
||||||
poll
|
poll
|
||||||
update
|
update
|
||||||
admin.sign_up
|
admin.sign_up
|
||||||
|
@ -48,7 +46,6 @@ class Notification < ApplicationRecord
|
||||||
reblog: [status: :reblog],
|
reblog: [status: :reblog],
|
||||||
mention: [mention: :status],
|
mention: [mention: :status],
|
||||||
favourite: [favourite: :status],
|
favourite: [favourite: :status],
|
||||||
reaction: [status_reaction: :status],
|
|
||||||
poll: [poll: :status],
|
poll: [poll: :status],
|
||||||
update: :status,
|
update: :status,
|
||||||
'admin.report': [report: :target_account],
|
'admin.report': [report: :target_account],
|
||||||
|
@ -64,7 +61,6 @@ class Notification < ApplicationRecord
|
||||||
belongs_to :follow, inverse_of: :notification
|
belongs_to :follow, inverse_of: :notification
|
||||||
belongs_to :follow_request, inverse_of: :notification
|
belongs_to :follow_request, inverse_of: :notification
|
||||||
belongs_to :favourite, inverse_of: :notification
|
belongs_to :favourite, inverse_of: :notification
|
||||||
belongs_to :status_reaction, inverse_of: :notification
|
|
||||||
belongs_to :poll, inverse_of: false
|
belongs_to :poll, inverse_of: false
|
||||||
belongs_to :report, inverse_of: false
|
belongs_to :report, inverse_of: false
|
||||||
end
|
end
|
||||||
|
@ -85,8 +81,6 @@ class Notification < ApplicationRecord
|
||||||
status&.reblog
|
status&.reblog
|
||||||
when :favourite
|
when :favourite
|
||||||
favourite&.status
|
favourite&.status
|
||||||
when :reaction
|
|
||||||
status_reaction&.status
|
|
||||||
when :mention
|
when :mention
|
||||||
mention&.status
|
mention&.status
|
||||||
when :poll
|
when :poll
|
||||||
|
@ -147,8 +141,6 @@ class Notification < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
alias reaction status_reaction
|
|
||||||
|
|
||||||
after_initialize :set_from_account
|
after_initialize :set_from_account
|
||||||
before_validation :set_from_account
|
before_validation :set_from_account
|
||||||
|
|
||||||
|
@ -158,7 +150,7 @@ class Notification < ApplicationRecord
|
||||||
return unless new_record?
|
return unless new_record?
|
||||||
|
|
||||||
case activity_type
|
case activity_type
|
||||||
when 'Status', 'Follow', 'Favourite', 'StatusReaction', 'FollowRequest', 'Poll', 'Report'
|
when 'Status', 'Follow', 'Favourite', 'FollowRequest', 'Poll', 'Report'
|
||||||
self.from_account_id = activity&.account_id
|
self.from_account_id = activity&.account_id
|
||||||
when 'Mention'
|
when 'Mention'
|
||||||
self.from_account_id = activity&.status&.account_id
|
self.from_account_id = activity&.status&.account_id
|
||||||
|
|
|
@ -77,7 +77,6 @@ class Status < ApplicationRecord
|
||||||
has_many :mentioned_accounts, through: :mentions, source: :account, class_name: 'Account'
|
has_many :mentioned_accounts, through: :mentions, source: :account, class_name: 'Account'
|
||||||
has_many :media_attachments, dependent: :nullify
|
has_many :media_attachments, dependent: :nullify
|
||||||
has_many :quoted, foreign_key: 'quote_id', class_name: 'Status', inverse_of: :quote, dependent: :nullify
|
has_many :quoted, foreign_key: 'quote_id', class_name: 'Status', inverse_of: :quote, dependent: :nullify
|
||||||
has_many :status_reactions, inverse_of: :status, dependent: :destroy
|
|
||||||
|
|
||||||
# The `dependent` option is enabled by the initial `mentions` association declaration
|
# The `dependent` option is enabled by the initial `mentions` association declaration
|
||||||
has_many :active_mentions, -> { active }, class_name: 'Mention', inverse_of: :status # rubocop:disable Rails/HasManyOrHasOneDependent
|
has_many :active_mentions, -> { active }, class_name: 'Mention', inverse_of: :status # rubocop:disable Rails/HasManyOrHasOneDependent
|
||||||
|
@ -306,16 +305,6 @@ class Status < ApplicationRecord
|
||||||
@emojis = CustomEmoji.from_text(fields.join(' '), account.domain) + (quote? ? CustomEmoji.from_text([quote.spoiler_text, quote.text].join(' '), quote.account.domain) : [])
|
@emojis = CustomEmoji.from_text(fields.join(' '), account.domain) + (quote? ? CustomEmoji.from_text([quote.spoiler_text, quote.text].join(' '), quote.account.domain) : [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def reactions(account = nil)
|
|
||||||
grouped_ordered_status_reactions.select(
|
|
||||||
[:name, :custom_emoji_id, 'COUNT(*) as count'].tap do |values|
|
|
||||||
values << value_for_reaction_me_column(account)
|
|
||||||
end
|
|
||||||
).to_a.tap do |records|
|
|
||||||
ActiveRecord::Associations::Preloader.new(records: records, associations: :custom_emoji).call
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def ordered_media_attachments
|
def ordered_media_attachments
|
||||||
if ordered_media_attachment_ids.nil?
|
if ordered_media_attachment_ids.nil?
|
||||||
# NOTE: sort Ruby-side to avoid hitting the database when the status is
|
# NOTE: sort Ruby-side to avoid hitting the database when the status is
|
||||||
|
@ -503,35 +492,6 @@ class Status < ApplicationRecord
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def grouped_ordered_status_reactions
|
|
||||||
status_reactions
|
|
||||||
.group(:status_id, :name, :custom_emoji_id)
|
|
||||||
.order(
|
|
||||||
Arel.sql('MIN(created_at)').asc
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def value_for_reaction_me_column(account)
|
|
||||||
if account.nil?
|
|
||||||
'FALSE AS me'
|
|
||||||
else
|
|
||||||
<<~SQL.squish
|
|
||||||
EXISTS(
|
|
||||||
SELECT 1
|
|
||||||
FROM status_reactions inner_reactions
|
|
||||||
WHERE inner_reactions.account_id = #{account.id}
|
|
||||||
AND inner_reactions.status_id = status_reactions.status_id
|
|
||||||
AND inner_reactions.name = status_reactions.name
|
|
||||||
AND (
|
|
||||||
inner_reactions.custom_emoji_id = status_reactions.custom_emoji_id
|
|
||||||
OR inner_reactions.custom_emoji_id IS NULL
|
|
||||||
AND status_reactions.custom_emoji_id IS NULL
|
|
||||||
)
|
|
||||||
) AS me
|
|
||||||
SQL
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_status_stat!(attrs)
|
def update_status_stat!(attrs)
|
||||||
return if marked_for_destruction? || destroyed?
|
return if marked_for_destruction? || destroyed?
|
||||||
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
# == Schema Information
|
|
||||||
#
|
|
||||||
# Table name: status_reactions
|
|
||||||
#
|
|
||||||
# id :bigint(8) not null, primary key
|
|
||||||
# account_id :bigint(8) not null
|
|
||||||
# status_id :bigint(8) not null
|
|
||||||
# name :string default(""), not null
|
|
||||||
# custom_emoji_id :bigint(8)
|
|
||||||
# created_at :datetime not null
|
|
||||||
# updated_at :datetime not null
|
|
||||||
#
|
|
||||||
class StatusReaction < ApplicationRecord
|
|
||||||
belongs_to :account
|
|
||||||
belongs_to :status, inverse_of: :status_reactions
|
|
||||||
belongs_to :custom_emoji, optional: true
|
|
||||||
|
|
||||||
has_one :notification, as: :activity, dependent: :destroy
|
|
||||||
|
|
||||||
validates :name, presence: true
|
|
||||||
validates_with StatusReactionValidator
|
|
||||||
|
|
||||||
before_validation do
|
|
||||||
self.status = status.reblog if status&.reblog?
|
|
||||||
end
|
|
||||||
|
|
||||||
before_validation :set_custom_emoji
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
# Sets custom_emoji to nil when disabled
|
|
||||||
def set_custom_emoji
|
|
||||||
self.custom_emoji = CustomEmoji.find_by(disabled: false, shortcode: name, domain: custom_emoji.domain) if name.present? && custom_emoji.present?
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class TagFeed < PublicFeed
|
class TagFeed < PublicFeed
|
||||||
LIMIT_PER_MODE = 4
|
LIMIT_PER_MODE = (ENV['MAX_FEED_HASHTAGS'] || 4).to_i
|
||||||
|
|
||||||
# @param [Tag] tag
|
# @param [Tag] tag
|
||||||
# @param [Account] account
|
# @param [Account] account
|
||||||
|
|
|
@ -51,6 +51,8 @@ class User < ApplicationRecord
|
||||||
last_sign_in_ip
|
last_sign_in_ip
|
||||||
skip_sign_in_token
|
skip_sign_in_token
|
||||||
filtered_languages
|
filtered_languages
|
||||||
|
admin
|
||||||
|
moderator
|
||||||
)
|
)
|
||||||
|
|
||||||
include LanguagesHelper
|
include LanguagesHelper
|
||||||
|
@ -342,6 +344,16 @@ class User < ApplicationRecord
|
||||||
Doorkeeper::AccessToken.by_resource_owner(self).in_batches do |batch|
|
Doorkeeper::AccessToken.by_resource_owner(self).in_batches do |batch|
|
||||||
batch.update_all(revoked_at: Time.now.utc)
|
batch.update_all(revoked_at: Time.now.utc)
|
||||||
Web::PushSubscription.where(access_token_id: batch).delete_all
|
Web::PushSubscription.where(access_token_id: batch).delete_all
|
||||||
|
|
||||||
|
# Revoke each access token for the Streaming API, since `update_all``
|
||||||
|
# doesn't trigger ActiveRecord Callbacks:
|
||||||
|
# TODO: #28793 Combine into a single topic
|
||||||
|
payload = Oj.dump(event: :kill)
|
||||||
|
redis.pipelined do |pipeline|
|
||||||
|
batch.ids.each do |id|
|
||||||
|
pipeline.publish("timeline:access_token:#{id}", payload)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ class UserSettings
|
||||||
setting :default_privacy, default: nil, in: %w(public unlisted private)
|
setting :default_privacy, default: nil, in: %w(public unlisted private)
|
||||||
setting :default_content_type, default: 'text/plain'
|
setting :default_content_type, default: 'text/plain'
|
||||||
setting :hide_followers_count, default: false
|
setting :hide_followers_count, default: false
|
||||||
setting :visible_reactions, default: 6
|
|
||||||
|
|
||||||
setting_inverse_alias :indexable, :noindex
|
setting_inverse_alias :indexable, :noindex
|
||||||
setting_inverse_alias :show_followers_count, :hide_followers_count
|
setting_inverse_alias :show_followers_count, :hide_followers_count
|
||||||
|
@ -45,7 +44,6 @@ class UserSettings
|
||||||
setting :follow, default: true
|
setting :follow, default: true
|
||||||
setting :reblog, default: false
|
setting :reblog, default: false
|
||||||
setting :favourite, default: false
|
setting :favourite, default: false
|
||||||
setting :reaction, default: false
|
|
||||||
setting :mention, default: true
|
setting :mention, default: true
|
||||||
setting :follow_request, default: true
|
setting :follow_request, default: true
|
||||||
setting :report, default: true
|
setting :report, default: true
|
||||||
|
|
|
@ -28,10 +28,6 @@ class StatusPolicy < ApplicationPolicy
|
||||||
show? && !blocking_author?
|
show? && !blocking_author?
|
||||||
end
|
end
|
||||||
|
|
||||||
def react?
|
|
||||||
show? && !blocking_author?
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy?
|
def destroy?
|
||||||
owned?
|
owned?
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class ActivityPub::EmojiReactionSerializer < ActivityPub::Serializer
|
|
||||||
attributes :id, :type, :actor, :content
|
|
||||||
attribute :virtual_object, key: :object
|
|
||||||
attribute :custom_emoji, key: :tag, unless: -> { object.custom_emoji.nil? }
|
|
||||||
|
|
||||||
def id
|
|
||||||
[ActivityPub::TagManager.instance.uri_for(object.account), '#emoji_reactions/', object.id].join
|
|
||||||
end
|
|
||||||
|
|
||||||
def type
|
|
||||||
'EmojiReact'
|
|
||||||
end
|
|
||||||
|
|
||||||
def actor
|
|
||||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
|
||||||
end
|
|
||||||
|
|
||||||
def virtual_object
|
|
||||||
ActivityPub::TagManager.instance.uri_for(object.status)
|
|
||||||
end
|
|
||||||
|
|
||||||
def content
|
|
||||||
if object.custom_emoji.nil?
|
|
||||||
object.name
|
|
||||||
else
|
|
||||||
":#{object.name}:"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
alias reaction content
|
|
||||||
|
|
||||||
# Akkoma (and possibly others) expect `tag` to be an array, so we can't just
|
|
||||||
# use the has_one shorthand because we need to wrap it into an array manually
|
|
||||||
def custom_emoji
|
|
||||||
[ActivityPub::EmojiSerializer.new(object.custom_emoji).serializable_hash]
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,19 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class ActivityPub::UndoEmojiReactionSerializer < ActivityPub::Serializer
|
|
||||||
attributes :id, :type, :actor
|
|
||||||
|
|
||||||
has_one :object, serializer: ActivityPub::EmojiReactionSerializer
|
|
||||||
|
|
||||||
def id
|
|
||||||
[ActivityPub::TagManager.instance.uri_for(object.account), '#emoji_reactions/', object.id, '/undo'].join
|
|
||||||
end
|
|
||||||
|
|
||||||
def type
|
|
||||||
'Undo'
|
|
||||||
end
|
|
||||||
|
|
||||||
def actor
|
|
||||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -5,8 +5,8 @@ class InitialStateSerializer < ActiveModel::Serializer
|
||||||
|
|
||||||
attributes :meta, :compose, :accounts,
|
attributes :meta, :compose, :accounts,
|
||||||
:media_attachments, :settings,
|
:media_attachments, :settings,
|
||||||
:max_toot_chars, :poll_limits,
|
:max_toot_chars, :max_feed_hashtags, :poll_limits,
|
||||||
:languages, :max_reactions
|
:languages
|
||||||
|
|
||||||
attribute :critical_updates_pending, if: -> { object&.role&.can?(:view_devops) && SoftwareUpdate.check_enabled? }
|
attribute :critical_updates_pending, if: -> { object&.role&.can?(:view_devops) && SoftwareUpdate.check_enabled? }
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ class InitialStateSerializer < ActiveModel::Serializer
|
||||||
StatusLengthValidator::MAX_CHARS
|
StatusLengthValidator::MAX_CHARS
|
||||||
end
|
end
|
||||||
|
|
||||||
def max_reactions
|
def max_feed_hashtags
|
||||||
StatusReactionValidator::LIMIT
|
TagFeed::LIMIT_PER_MODE
|
||||||
end
|
end
|
||||||
|
|
||||||
def poll_limits
|
def poll_limits
|
||||||
|
@ -50,7 +50,6 @@ class InitialStateSerializer < ActiveModel::Serializer
|
||||||
store[:default_content_type] = object_account_user.setting_default_content_type
|
store[:default_content_type] = object_account_user.setting_default_content_type
|
||||||
store[:system_emoji_font] = object_account_user.setting_system_emoji_font
|
store[:system_emoji_font] = object_account_user.setting_system_emoji_font
|
||||||
store[:show_trends] = Setting.trends && object_account_user.setting_trends
|
store[:show_trends] = Setting.trends && object_account_user.setting_trends
|
||||||
store[:visible_reactions] = object_account_user.setting_visible_reactions
|
|
||||||
else
|
else
|
||||||
store[:auto_play_gif] = Setting.auto_play_gif
|
store[:auto_play_gif] = Setting.auto_play_gif
|
||||||
store[:display_media] = Setting.display_media
|
store[:display_media] = Setting.display_media
|
||||||
|
|
|
@ -82,10 +82,6 @@ class REST::InstanceSerializer < ActiveModel::Serializer
|
||||||
translation: {
|
translation: {
|
||||||
enabled: TranslationService.configured?,
|
enabled: TranslationService.configured?,
|
||||||
},
|
},
|
||||||
|
|
||||||
reactions: {
|
|
||||||
max_reactions: StatusReactionValidator::LIMIT,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|