Merge pull request #3472 from glitch-soc/glitch-soc/merge-upstream
Merge upstream changes up to 73fc8d34d98a80cfb32d3c7c5dc4794fad5470d5
This commit is contained in:
commit
96aa458d22
200
Dockerfile
200
Dockerfile
@ -25,8 +25,8 @@ FROM ${BASE_REGISTRY}/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim AS node
|
|||||||
FROM ${BASE_REGISTRY}/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} AS ruby
|
FROM ${BASE_REGISTRY}/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} AS ruby
|
||||||
|
|
||||||
# Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA
|
# Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA
|
||||||
# Example: v4.3.0-nightly.2023.11.09+pr-123456
|
# Example: v4.3.0-nightly.2023-11-09+pr-123456
|
||||||
# Overwrite existence of 'alpha.X' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"]
|
# Overwrite existence of 'alpha.X' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023-11-09"]
|
||||||
ARG MASTODON_VERSION_PRERELEASE=""
|
ARG MASTODON_VERSION_PRERELEASE=""
|
||||||
# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="pr-123456"]
|
# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="pr-123456"]
|
||||||
ARG MASTODON_VERSION_METADATA=""
|
ARG MASTODON_VERSION_METADATA=""
|
||||||
@ -48,29 +48,27 @@ ARG GID="991"
|
|||||||
|
|
||||||
# Apply Mastodon build options based on options above
|
# Apply Mastodon build options based on options above
|
||||||
ENV \
|
ENV \
|
||||||
# Apply Mastodon version information
|
|
||||||
MASTODON_VERSION_PRERELEASE="${MASTODON_VERSION_PRERELEASE}" \
|
MASTODON_VERSION_PRERELEASE="${MASTODON_VERSION_PRERELEASE}" \
|
||||||
MASTODON_VERSION_METADATA="${MASTODON_VERSION_METADATA}" \
|
MASTODON_VERSION_METADATA="${MASTODON_VERSION_METADATA}" \
|
||||||
SOURCE_COMMIT="${SOURCE_COMMIT}" \
|
SOURCE_COMMIT="${SOURCE_COMMIT}" \
|
||||||
# Apply Mastodon static files and YJIT options
|
RAILS_SERVE_STATIC_FILES="${RAILS_SERVE_STATIC_FILES}" \
|
||||||
RAILS_SERVE_STATIC_FILES=${RAILS_SERVE_STATIC_FILES} \
|
RUBY_YJIT_ENABLE="${RUBY_YJIT_ENABLE}" \
|
||||||
RUBY_YJIT_ENABLE=${RUBY_YJIT_ENABLE} \
|
TZ="${TZ}"
|
||||||
# Apply timezone
|
|
||||||
TZ=${TZ}
|
|
||||||
|
|
||||||
|
# Configure runtime environment
|
||||||
|
# BIND: IP to bind Mastodon to when serving traffic
|
||||||
|
# NODE_ENV/RAILS_ENV: production settings for Node.js and Ruby on Rails
|
||||||
|
# DEBIAN_FRONTEND: suppress interactive prompts
|
||||||
|
# PATH: add Ruby and Mastodon installation directories
|
||||||
|
# MALLOC_CONF: optimize jemalloc 5.x performance
|
||||||
|
# MASTODON_SIDEKIQ_READY_FILENAME: Sidekiq readiness check filename for Kubernetes
|
||||||
ENV \
|
ENV \
|
||||||
# Configure the IP to bind Mastodon to when serving traffic
|
|
||||||
BIND="0.0.0.0" \
|
BIND="0.0.0.0" \
|
||||||
# Use production settings for Yarn, Node.js and related tools
|
|
||||||
NODE_ENV="production" \
|
NODE_ENV="production" \
|
||||||
# Use production settings for Ruby on Rails
|
|
||||||
RAILS_ENV="production" \
|
RAILS_ENV="production" \
|
||||||
# Add Ruby and Mastodon installation to the PATH
|
|
||||||
DEBIAN_FRONTEND="noninteractive" \
|
DEBIAN_FRONTEND="noninteractive" \
|
||||||
PATH="${PATH}:/opt/ruby/bin:/opt/mastodon/bin" \
|
PATH="${PATH}:/opt/ruby/bin:/opt/mastodon/bin" \
|
||||||
# Optimize jemalloc 5.x performance
|
|
||||||
MALLOC_CONF="narenas:2,background_thread:true,thp:never,dirty_decay_ms:1000,muzzy_decay_ms:0" \
|
MALLOC_CONF="narenas:2,background_thread:true,thp:never,dirty_decay_ms:1000,muzzy_decay_ms:0" \
|
||||||
# Sidekiq will touch tmp/sidekiq_process_has_started_and_will_begin_processing_jobs to indicate it is ready. This can be used for a readiness check in Kubernetes
|
|
||||||
MASTODON_SIDEKIQ_READY_FILENAME=sidekiq_process_has_started_and_will_begin_processing_jobs
|
MASTODON_SIDEKIQ_READY_FILENAME=sidekiq_process_has_started_and_will_begin_processing_jobs
|
||||||
|
|
||||||
# Set default shell used for running commands
|
# Set default shell used for running commands
|
||||||
@ -99,10 +97,10 @@ RUN \
|
|||||||
# Mount Apt cache and lib directories from Docker buildx caches
|
# Mount Apt cache and lib directories from Docker buildx caches
|
||||||
--mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
|
--mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
|
||||||
--mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
|
--mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
|
||||||
# Apt update & upgrade to check for security updates to Debian image
|
# Update package list and upgrade system packages
|
||||||
apt-get update; \
|
apt-get update; \
|
||||||
apt-get dist-upgrade -yq; \
|
apt-get dist-upgrade -yq; \
|
||||||
# Install jemalloc, curl and other necessary components
|
# Install jemalloc and other necessary components
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
curl \
|
curl \
|
||||||
file \
|
file \
|
||||||
@ -112,6 +110,42 @@ RUN \
|
|||||||
tini \
|
tini \
|
||||||
tzdata \
|
tzdata \
|
||||||
wget \
|
wget \
|
||||||
|
# Mastodon components
|
||||||
|
libexpat1 \
|
||||||
|
libglib2.0-0t64 \
|
||||||
|
libicu76 \
|
||||||
|
libidn12 \
|
||||||
|
libpq5 \
|
||||||
|
libreadline8t64 \
|
||||||
|
libssl3t64 \
|
||||||
|
libyaml-0-2 \
|
||||||
|
# libvips components
|
||||||
|
libcgif0 \
|
||||||
|
libexif12 \
|
||||||
|
libheif1 \
|
||||||
|
libhwy1t64 \
|
||||||
|
libimagequant0 \
|
||||||
|
libjpeg62-turbo \
|
||||||
|
liblcms2-2 \
|
||||||
|
libspng0 \
|
||||||
|
libtiff6 \
|
||||||
|
libwebp7 \
|
||||||
|
libwebpdemux2 \
|
||||||
|
libwebpmux3 \
|
||||||
|
# ffmpeg components
|
||||||
|
libdav1d7 \
|
||||||
|
libmp3lame0 \
|
||||||
|
libopencore-amrnb0 \
|
||||||
|
libopencore-amrwb0 \
|
||||||
|
libopus0 \
|
||||||
|
libsnappy1v5 \
|
||||||
|
libtheora0 \
|
||||||
|
libvorbis0a \
|
||||||
|
libvorbisenc2 \
|
||||||
|
libvorbisfile3 \
|
||||||
|
libvpx9 \
|
||||||
|
libx264-164 \
|
||||||
|
libx265-215 \
|
||||||
; \
|
; \
|
||||||
# Patch Ruby to use jemalloc
|
# Patch Ruby to use jemalloc
|
||||||
patchelf --add-needed libjemalloc.so.2 /usr/local/bin/ruby; \
|
patchelf --add-needed libjemalloc.so.2 /usr/local/bin/ruby; \
|
||||||
@ -120,42 +154,37 @@ RUN \
|
|||||||
patchelf \
|
patchelf \
|
||||||
;
|
;
|
||||||
|
|
||||||
# Create temporary build layer from base image
|
# Build stage for media libraries (libvips, ffmpeg)
|
||||||
FROM ruby AS build
|
FROM ${BASE_REGISTRY}/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} AS media-build
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
|
|
||||||
|
# Set default shell used for running commands
|
||||||
|
SHELL ["/bin/bash", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||||
|
|
||||||
# hadolint ignore=DL3008
|
# hadolint ignore=DL3008
|
||||||
RUN \
|
RUN \
|
||||||
# Mount Apt cache and lib directories from Docker buildx caches
|
--mount=type=cache,id=apt-native-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
|
||||||
--mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
|
--mount=type=cache,id=apt-native-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
|
||||||
--mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
|
# Remove automatic apt cache Docker cleanup scripts
|
||||||
# Install build tools and bundler dependencies from APT
|
rm -f /etc/apt/apt.conf.d/docker-clean; \
|
||||||
|
# Install build tools for native libraries
|
||||||
|
apt-get update; \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
autoconf \
|
autoconf \
|
||||||
automake \
|
automake \
|
||||||
build-essential \
|
build-essential \
|
||||||
cmake \
|
|
||||||
git \
|
|
||||||
libgdbm-dev \
|
|
||||||
libglib2.0-dev \
|
|
||||||
libgmp-dev \
|
|
||||||
libicu-dev \
|
|
||||||
libidn-dev \
|
|
||||||
libpq-dev \
|
|
||||||
libssl-dev \
|
|
||||||
libtool \
|
libtool \
|
||||||
libyaml-dev \
|
|
||||||
meson \
|
meson \
|
||||||
nasm \
|
nasm \
|
||||||
pkg-config \
|
pkg-config \
|
||||||
shared-mime-info \
|
|
||||||
xz-utils \
|
xz-utils \
|
||||||
# libvips components
|
# libvips components
|
||||||
libcgif-dev \
|
libcgif-dev \
|
||||||
libexif-dev \
|
libexif-dev \
|
||||||
libexpat1-dev \
|
libexpat1-dev \
|
||||||
libgirepository1.0-dev \
|
libgirepository1.0-dev \
|
||||||
|
libglib2.0-dev \
|
||||||
libheif-dev \
|
libheif-dev \
|
||||||
libhwy-dev \
|
libhwy-dev \
|
||||||
libimagequant-dev \
|
libimagequant-dev \
|
||||||
@ -176,8 +205,8 @@ RUN \
|
|||||||
libx265-dev \
|
libx265-dev \
|
||||||
;
|
;
|
||||||
|
|
||||||
# Create temporary libvips specific build layer from build layer
|
# Create temporary libvips specific build layer
|
||||||
FROM build AS libvips
|
FROM media-build AS libvips
|
||||||
|
|
||||||
# libvips version to compile, change with [--build-arg VIPS_VERSION="8.15.2"]
|
# libvips version to compile, change with [--build-arg VIPS_VERSION="8.15.2"]
|
||||||
# renovate: datasource=github-releases depName=libvips packageName=libvips/libvips
|
# renovate: datasource=github-releases depName=libvips packageName=libvips/libvips
|
||||||
@ -192,15 +221,16 @@ RUN tar xf vips-${VIPS_VERSION}.tar.xz;
|
|||||||
|
|
||||||
WORKDIR /usr/local/libvips/src/vips-${VIPS_VERSION}
|
WORKDIR /usr/local/libvips/src/vips-${VIPS_VERSION}
|
||||||
|
|
||||||
# Configure and compile libvips
|
# Configure libvips
|
||||||
RUN \
|
RUN meson setup build --prefix /usr/local/libvips --libdir=lib -Ddeprecated=false -Dintrospection=disabled -Dmodules=disabled -Dexamples=false
|
||||||
meson setup build --prefix /usr/local/libvips --libdir=lib -Ddeprecated=false -Dintrospection=disabled -Dmodules=disabled -Dexamples=false; \
|
|
||||||
cd build; \
|
|
||||||
ninja; \
|
|
||||||
ninja install;
|
|
||||||
|
|
||||||
# Create temporary ffmpeg specific build layer from build layer
|
WORKDIR /usr/local/libvips/src/vips-${VIPS_VERSION}/build
|
||||||
FROM build AS ffmpeg
|
|
||||||
|
# Compile and install libvips
|
||||||
|
RUN ninja && ninja install
|
||||||
|
|
||||||
|
# Create temporary ffmpeg specific build layer
|
||||||
|
FROM media-build AS ffmpeg
|
||||||
|
|
||||||
# ffmpeg version to compile, change with [--build-arg FFMPEG_VERSION="7.0.x"]
|
# ffmpeg version to compile, change with [--build-arg FFMPEG_VERSION="7.0.x"]
|
||||||
# renovate: datasource=repology depName=ffmpeg packageName=openpkg_current/ffmpeg
|
# renovate: datasource=repology depName=ffmpeg packageName=openpkg_current/ffmpeg
|
||||||
@ -241,17 +271,48 @@ RUN \
|
|||||||
--enable-shared \
|
--enable-shared \
|
||||||
--enable-version3 \
|
--enable-version3 \
|
||||||
; \
|
; \
|
||||||
make -j$(nproc); \
|
make -j"$(nproc)"; \
|
||||||
make install;
|
make install;
|
||||||
|
|
||||||
|
# Create temporary build layer from base image for Ruby dependencies
|
||||||
|
FROM ruby AS ruby-build
|
||||||
|
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
|
||||||
|
# hadolint ignore=DL3008
|
||||||
|
RUN \
|
||||||
|
# Mount Apt cache and lib directories from Docker buildx caches
|
||||||
|
--mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
|
||||||
|
--mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
|
||||||
|
# Install build tools and bundler dependencies from APT
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
git \
|
||||||
|
libgdbm-dev \
|
||||||
|
libgmp-dev \
|
||||||
|
libicu-dev \
|
||||||
|
libidn-dev \
|
||||||
|
libpq-dev \
|
||||||
|
libssl-dev \
|
||||||
|
libyaml-dev \
|
||||||
|
shared-mime-info \
|
||||||
|
zlib1g-dev \
|
||||||
|
;
|
||||||
|
|
||||||
# Create temporary bundler specific build layer from build layer
|
# Create temporary bundler specific build layer from build layer
|
||||||
FROM build AS bundler
|
FROM ruby-build AS bundler
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
|
|
||||||
# Copy Gemfile config into working directory
|
# Copy Gemfile config into working directory
|
||||||
COPY Gemfile* /opt/mastodon/
|
COPY Gemfile* /opt/mastodon/
|
||||||
|
|
||||||
|
# Copy libvips for gems that need it during install
|
||||||
|
COPY --from=libvips /usr/local/libvips/lib /usr/local/lib
|
||||||
|
COPY --from=libvips /usr/local/libvips/include /usr/local/include
|
||||||
|
|
||||||
|
RUN ldconfig
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
# Mount Ruby Gem caches
|
# Mount Ruby Gem caches
|
||||||
--mount=type=cache,id=gem-cache-${TARGETPLATFORM},target=/usr/local/bundle/cache/,sharing=locked \
|
--mount=type=cache,id=gem-cache-${TARGETPLATFORM},target=/usr/local/bundle/cache/,sharing=locked \
|
||||||
@ -267,7 +328,7 @@ RUN \
|
|||||||
bundle install -j"$(nproc)";
|
bundle install -j"$(nproc)";
|
||||||
|
|
||||||
# Create temporary assets build layer from build layer
|
# Create temporary assets build layer from build layer
|
||||||
FROM build AS precompiler
|
FROM ruby-build AS precompiler
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
|
|
||||||
@ -311,53 +372,6 @@ FROM ruby AS mastodon
|
|||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
|
|
||||||
# hadolint ignore=DL3008
|
|
||||||
RUN \
|
|
||||||
# Mount Apt cache and lib directories from Docker buildx caches
|
|
||||||
--mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
|
|
||||||
--mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
|
|
||||||
# Mount Corepack and Yarn caches from Docker buildx caches
|
|
||||||
--mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
|
|
||||||
--mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
|
|
||||||
# Apt update install non-dev versions of necessary components
|
|
||||||
apt-get install -y --no-install-recommends \
|
|
||||||
libexpat1 \
|
|
||||||
libglib2.0-0t64 \
|
|
||||||
libicu76 \
|
|
||||||
libidn12 \
|
|
||||||
libpq5 \
|
|
||||||
libreadline8t64 \
|
|
||||||
libssl3t64 \
|
|
||||||
libyaml-0-2 \
|
|
||||||
# libvips components
|
|
||||||
libcgif0 \
|
|
||||||
libexif12 \
|
|
||||||
libheif1 \
|
|
||||||
libhwy1t64 \
|
|
||||||
libimagequant0 \
|
|
||||||
libjpeg62-turbo \
|
|
||||||
liblcms2-2 \
|
|
||||||
libspng0 \
|
|
||||||
libtiff6 \
|
|
||||||
libwebp7 \
|
|
||||||
libwebpdemux2 \
|
|
||||||
libwebpmux3 \
|
|
||||||
# ffmpeg components
|
|
||||||
libdav1d7 \
|
|
||||||
libmp3lame0 \
|
|
||||||
libopencore-amrnb0 \
|
|
||||||
libopencore-amrwb0 \
|
|
||||||
libopus0 \
|
|
||||||
libsnappy1v5 \
|
|
||||||
libtheora0 \
|
|
||||||
libvorbis0a \
|
|
||||||
libvorbisenc2 \
|
|
||||||
libvorbisfile3 \
|
|
||||||
libvpx9 \
|
|
||||||
libx264-164 \
|
|
||||||
libx265-215 \
|
|
||||||
;
|
|
||||||
|
|
||||||
# Copy Mastodon sources into final layer
|
# Copy Mastodon sources into final layer
|
||||||
COPY . /opt/mastodon/
|
COPY . /opt/mastodon/
|
||||||
|
|
||||||
|
|||||||
4
Gemfile
4
Gemfile
@ -102,10 +102,10 @@ gem 'rdf-normalize', '~> 0.5'
|
|||||||
|
|
||||||
gem 'prometheus_exporter', '~> 2.2', require: false
|
gem 'prometheus_exporter', '~> 2.2', require: false
|
||||||
|
|
||||||
gem 'opentelemetry-api', '~> 1.8.0'
|
gem 'opentelemetry-api', '~> 1.9.0'
|
||||||
|
|
||||||
group :opentelemetry do
|
group :opentelemetry do
|
||||||
gem 'opentelemetry-exporter-otlp', '~> 0.32.0', require: false
|
gem 'opentelemetry-exporter-otlp', '~> 0.33.0', require: false
|
||||||
gem 'opentelemetry-instrumentation-active_job', '~> 0.10.0', require: false
|
gem 'opentelemetry-instrumentation-active_job', '~> 0.10.0', require: false
|
||||||
gem 'opentelemetry-instrumentation-active_model_serializers', '~> 0.24.0', require: false
|
gem 'opentelemetry-instrumentation-active_model_serializers', '~> 0.24.0', require: false
|
||||||
gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.24.0', require: false
|
gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.24.0', require: false
|
||||||
|
|||||||
29
Gemfile.lock
29
Gemfile.lock
@ -99,7 +99,7 @@ GEM
|
|||||||
ast (2.4.3)
|
ast (2.4.3)
|
||||||
attr_required (1.0.2)
|
attr_required (1.0.2)
|
||||||
aws-eventstream (1.4.0)
|
aws-eventstream (1.4.0)
|
||||||
aws-partitions (1.1227.0)
|
aws-partitions (1.1236.0)
|
||||||
aws-sdk-core (3.244.0)
|
aws-sdk-core (3.244.0)
|
||||||
aws-eventstream (~> 1, >= 1.3.0)
|
aws-eventstream (~> 1, >= 1.3.0)
|
||||||
aws-partitions (~> 1, >= 1.992.0)
|
aws-partitions (~> 1, >= 1.992.0)
|
||||||
@ -111,7 +111,7 @@ GEM
|
|||||||
aws-sdk-kms (1.123.0)
|
aws-sdk-kms (1.123.0)
|
||||||
aws-sdk-core (~> 3, >= 3.244.0)
|
aws-sdk-core (~> 3, >= 3.244.0)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sdk-s3 (1.217.0)
|
aws-sdk-s3 (1.219.0)
|
||||||
aws-sdk-core (~> 3, >= 3.244.0)
|
aws-sdk-core (~> 3, >= 3.244.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
@ -278,7 +278,7 @@ GEM
|
|||||||
raabro (~> 1.4)
|
raabro (~> 1.4)
|
||||||
globalid (1.3.0)
|
globalid (1.3.0)
|
||||||
activesupport (>= 6.1)
|
activesupport (>= 6.1)
|
||||||
google-protobuf (4.34.0)
|
google-protobuf (4.34.1)
|
||||||
bigdecimal
|
bigdecimal
|
||||||
rake (~> 13.3)
|
rake (~> 13.3)
|
||||||
googleapis-common-protos-types (1.22.0)
|
googleapis-common-protos-types (1.22.0)
|
||||||
@ -451,7 +451,7 @@ GEM
|
|||||||
mime-types-data (3.2026.0317)
|
mime-types-data (3.2026.0317)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
mini_portile2 (2.8.9)
|
mini_portile2 (2.8.9)
|
||||||
minitest (6.0.2)
|
minitest (6.0.3)
|
||||||
drb (~> 2.0)
|
drb (~> 2.0)
|
||||||
prism (~> 1.5)
|
prism (~> 1.5)
|
||||||
msgpack (1.8.0)
|
msgpack (1.8.0)
|
||||||
@ -509,11 +509,11 @@ GEM
|
|||||||
openssl (4.0.1)
|
openssl (4.0.1)
|
||||||
openssl-signature_algorithm (1.3.0)
|
openssl-signature_algorithm (1.3.0)
|
||||||
openssl (> 2.0)
|
openssl (> 2.0)
|
||||||
opentelemetry-api (1.8.0)
|
opentelemetry-api (1.9.0)
|
||||||
logger
|
logger
|
||||||
opentelemetry-common (0.23.0)
|
opentelemetry-common (0.24.0)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-exporter-otlp (0.32.0)
|
opentelemetry-exporter-otlp (0.33.0)
|
||||||
google-protobuf (>= 3.18)
|
google-protobuf (>= 3.18)
|
||||||
googleapis-common-protos-types (~> 1.3)
|
googleapis-common-protos-types (~> 1.3)
|
||||||
opentelemetry-api (~> 1.1)
|
opentelemetry-api (~> 1.1)
|
||||||
@ -576,14 +576,15 @@ GEM
|
|||||||
opentelemetry-instrumentation-base (~> 0.25)
|
opentelemetry-instrumentation-base (~> 0.25)
|
||||||
opentelemetry-instrumentation-sidekiq (0.28.1)
|
opentelemetry-instrumentation-sidekiq (0.28.1)
|
||||||
opentelemetry-instrumentation-base (~> 0.25)
|
opentelemetry-instrumentation-base (~> 0.25)
|
||||||
opentelemetry-registry (0.4.0)
|
opentelemetry-registry (0.5.0)
|
||||||
opentelemetry-api (~> 1.1)
|
opentelemetry-api (~> 1.1)
|
||||||
opentelemetry-sdk (1.10.0)
|
opentelemetry-sdk (1.11.0)
|
||||||
|
logger
|
||||||
opentelemetry-api (~> 1.1)
|
opentelemetry-api (~> 1.1)
|
||||||
opentelemetry-common (~> 0.20)
|
opentelemetry-common (~> 0.20)
|
||||||
opentelemetry-registry (~> 0.2)
|
opentelemetry-registry (~> 0.2)
|
||||||
opentelemetry-semantic_conventions
|
opentelemetry-semantic_conventions
|
||||||
opentelemetry-semantic_conventions (1.36.0)
|
opentelemetry-semantic_conventions (1.37.0)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
ostruct (0.6.3)
|
ostruct (0.6.3)
|
||||||
@ -851,8 +852,8 @@ GEM
|
|||||||
concurrent-ruby
|
concurrent-ruby
|
||||||
zeitwerk
|
zeitwerk
|
||||||
stringio (3.2.0)
|
stringio (3.2.0)
|
||||||
strong_migrations (2.5.2)
|
strong_migrations (2.6.0)
|
||||||
activerecord (>= 7.1)
|
activerecord (>= 7.2)
|
||||||
swd (2.0.3)
|
swd (2.0.3)
|
||||||
activesupport (>= 3)
|
activesupport (>= 3)
|
||||||
attr_required (>= 0.0.5)
|
attr_required (>= 0.0.5)
|
||||||
@ -1020,8 +1021,8 @@ DEPENDENCIES
|
|||||||
omniauth-rails_csrf_protection (~> 2.0)
|
omniauth-rails_csrf_protection (~> 2.0)
|
||||||
omniauth-saml (~> 2.0)
|
omniauth-saml (~> 2.0)
|
||||||
omniauth_openid_connect (~> 0.8.0)
|
omniauth_openid_connect (~> 0.8.0)
|
||||||
opentelemetry-api (~> 1.8.0)
|
opentelemetry-api (~> 1.9.0)
|
||||||
opentelemetry-exporter-otlp (~> 0.32.0)
|
opentelemetry-exporter-otlp (~> 0.33.0)
|
||||||
opentelemetry-instrumentation-active_job (~> 0.10.0)
|
opentelemetry-instrumentation-active_job (~> 0.10.0)
|
||||||
opentelemetry-instrumentation-active_model_serializers (~> 0.24.0)
|
opentelemetry-instrumentation-active_model_serializers (~> 0.24.0)
|
||||||
opentelemetry-instrumentation-concurrent_ruby (~> 0.24.0)
|
opentelemetry-instrumentation-concurrent_ruby (~> 0.24.0)
|
||||||
|
|||||||
@ -53,7 +53,7 @@ export interface BaseApiAccountJSON {
|
|||||||
header_static: string;
|
header_static: string;
|
||||||
header_description: string;
|
header_description: string;
|
||||||
id: string;
|
id: string;
|
||||||
last_status_at: string;
|
last_status_at: string | null;
|
||||||
locked: boolean;
|
locked: boolean;
|
||||||
show_media: boolean;
|
show_media: boolean;
|
||||||
show_media_replies: boolean;
|
show_media_replies: boolean;
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import { useRelationship } from 'flavours/glitch/hooks/useRelationship';
|
|||||||
import type { Relationship } from 'flavours/glitch/models/relationship';
|
import type { Relationship } from 'flavours/glitch/models/relationship';
|
||||||
|
|
||||||
import { EmojiHTML } from '../emoji/html';
|
import { EmojiHTML } from '../emoji/html';
|
||||||
import { FamiliarFollowers } from '../familiar_followers';
|
|
||||||
import { FollowButton } from '../follow_button';
|
import { FollowButton } from '../follow_button';
|
||||||
import { FormattedDateWrapper } from '../formatted_date';
|
import { FormattedDateWrapper } from '../formatted_date';
|
||||||
import { NumberFields, NumberFieldsItem } from '../number_fields';
|
import { NumberFields, NumberFieldsItem } from '../number_fields';
|
||||||
@ -31,10 +30,11 @@ interface Props {
|
|||||||
accountId: string | undefined;
|
accountId: string | undefined;
|
||||||
stats?: Stat[];
|
stats?: Stat[];
|
||||||
renderButton?: (options: RenderButtonOptions) => React.ReactNode;
|
renderButton?: (options: RenderButtonOptions) => React.ReactNode;
|
||||||
|
withBio?: boolean;
|
||||||
withBorder?: boolean;
|
withBorder?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_STATS: Stat[] = ['followers', 'following', 'joined'];
|
const DEFAULT_STATS: Stat[] = ['followers', 'posts', 'last-active'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extended account list item with bio, verified link badge,
|
* Extended account list item with bio, verified link badge,
|
||||||
@ -46,6 +46,7 @@ const DEFAULT_STATS: Stat[] = ['followers', 'following', 'joined'];
|
|||||||
export const AccountListItem: React.FC<Props> = ({
|
export const AccountListItem: React.FC<Props> = ({
|
||||||
accountId,
|
accountId,
|
||||||
stats = DEFAULT_STATS,
|
stats = DEFAULT_STATS,
|
||||||
|
withBio = true,
|
||||||
withBorder = true,
|
withBorder = true,
|
||||||
renderButton = defaultRenderButton,
|
renderButton = defaultRenderButton,
|
||||||
}) => {
|
}) => {
|
||||||
@ -147,11 +148,15 @@ export const AccountListItem: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{account.last_status_at ? (
|
||||||
<RelativeTimestamp
|
<RelativeTimestamp
|
||||||
long
|
long
|
||||||
timestamp={account.last_status_at}
|
timestamp={account.last_status_at}
|
||||||
noFuture
|
noFuture
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
'-'
|
||||||
|
)}
|
||||||
</NumberFieldsItem>
|
</NumberFieldsItem>
|
||||||
)}
|
)}
|
||||||
{firstVerifiedField && (
|
{firstVerifiedField && (
|
||||||
@ -161,8 +166,7 @@ export const AccountListItem: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</NumberFields>
|
</NumberFields>
|
||||||
<FamiliarFollowers accountId={accountId} />
|
{withBio && account.note.length > 0 && (
|
||||||
{account.note.length > 0 && (
|
|
||||||
<EmojiHTML
|
<EmojiHTML
|
||||||
className={classNames(classes.bio, 'translate')}
|
className={classNames(classes.bio, 'translate')}
|
||||||
htmlString={account.note_emojified}
|
htmlString={account.note_emojified}
|
||||||
|
|||||||
@ -8,13 +8,6 @@
|
|||||||
&[data-with-border='true'] {
|
&[data-with-border='true'] {
|
||||||
border-bottom: 1px solid var(--color-border-primary);
|
border-bottom: 1px solid var(--color-border-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.account__note) {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 3;
|
|
||||||
line-clamp: 3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
@ -40,6 +33,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bio {
|
.bio {
|
||||||
|
overflow: hidden;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
line-clamp: 3;
|
||||||
|
|
||||||
:any-link {
|
:any-link {
|
||||||
color: var(--color-text-status-links);
|
color: var(--color-text-status-links);
|
||||||
|
|
||||||
|
|||||||
@ -73,7 +73,7 @@ const BackButton: React.FC<{
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
title?: string;
|
title?: React.ReactNode;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
iconComponent?: IconProp;
|
iconComponent?: IconProp;
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
|
|||||||
@ -3,16 +3,20 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
padding: 20px;
|
padding: 24px;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: var(--color-text-primary);
|
color: var(--color-text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
max-width: 370px;
|
||||||
|
|
||||||
svg,
|
svg,
|
||||||
img {
|
img {
|
||||||
width: 240px;
|
width: 200px;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
object-fit: contain;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
@ -20,11 +24,14 @@
|
|||||||
h3 {
|
h3 {
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
text-wrap: balance;
|
||||||
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
font-size: 15px;
|
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
|
font-size: 15px;
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
|
text-wrap: pretty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
.menuButton {
|
.menuButton {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset-inline-end: 0;
|
inset-inline-end: 1px;
|
||||||
top: 0;
|
top: 1px;
|
||||||
padding: 9px;
|
padding: 7px;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
// Subtle divider line separating the button from the input field
|
// Subtle divider line separating the button from the input field
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
.copyButton {
|
.copyButton {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset-inline-end: 0;
|
inset-inline-end: 1px;
|
||||||
top: 0;
|
top: 1px;
|
||||||
padding: 9px;
|
padding: 7px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,18 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { openModal } from '@/flavours/glitch/actions/modal';
|
||||||
|
import { Button } from '@/flavours/glitch/components/button';
|
||||||
import { EmptyState } from '@/flavours/glitch/components/empty_state';
|
import { EmptyState } from '@/flavours/glitch/components/empty_state';
|
||||||
import { LimitedAccountHint } from '@/flavours/glitch/features/account_timeline/components/limited_account_hint';
|
import { LimitedAccountHint } from '@/flavours/glitch/features/account_timeline/components/limited_account_hint';
|
||||||
import { areCollectionsEnabled } from '@/flavours/glitch/features/collections/utils';
|
import { areCollectionsEnabled } from '@/flavours/glitch/features/collections/utils';
|
||||||
import { useCurrentAccountId } from '@/flavours/glitch/hooks/useAccountId';
|
import { useCurrentAccountId } from '@/flavours/glitch/hooks/useAccountId';
|
||||||
import { useTheme } from '@/flavours/glitch/hooks/useTheme';
|
import { useTheme } from '@/flavours/glitch/hooks/useTheme';
|
||||||
|
import { useAppDispatch } from '@/flavours/glitch/store';
|
||||||
import ElephantDarkImage from '@/images/elephant_ui_dark.svg?react';
|
import ElephantDarkImage from '@/images/elephant_ui_dark.svg?react';
|
||||||
import ElephantLightImage from '@/images/elephant_ui_light.svg?react';
|
import ElephantLightImage from '@/images/elephant_ui_light.svg?react';
|
||||||
|
|
||||||
@ -16,6 +21,7 @@ interface EmptyMessageProps {
|
|||||||
hidden: boolean;
|
hidden: boolean;
|
||||||
blockedBy: boolean;
|
blockedBy: boolean;
|
||||||
accountId?: string;
|
accountId?: string;
|
||||||
|
withoutAddCollectionButton?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
||||||
@ -23,6 +29,7 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
suspended,
|
suspended,
|
||||||
hidden,
|
hidden,
|
||||||
blockedBy,
|
blockedBy,
|
||||||
|
withoutAddCollectionButton,
|
||||||
}) => {
|
}) => {
|
||||||
const { acct } = useParams<{ acct?: string }>();
|
const { acct } = useParams<{ acct?: string }>();
|
||||||
const me = useCurrentAccountId();
|
const me = useCurrentAccountId();
|
||||||
@ -30,6 +37,17 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
const ElephantImage =
|
const ElephantImage =
|
||||||
theme === 'dark' ? ElephantDarkImage : ElephantLightImage;
|
theme === 'dark' ? ElephantDarkImage : ElephantLightImage;
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const confirmHideFeaturedTab = useCallback(() => {
|
||||||
|
void dispatch(
|
||||||
|
openModal({
|
||||||
|
modalType: 'ACCOUNT_HIDE_FEATURED_TAB',
|
||||||
|
modalProps: {},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
if (!accountId) {
|
if (!accountId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -49,17 +67,31 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
image={image}
|
image={image}
|
||||||
title={
|
title={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.account_featured_self.no_collections'
|
id='empty_column.account_featured_self.showcase_accounts'
|
||||||
defaultMessage='No collections yet'
|
defaultMessage='Showcase your favorite accounts'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
message={
|
||||||
|
<FormattedMessage
|
||||||
|
id='empty_column.account_featured_self.showcase_accounts_desc'
|
||||||
|
defaultMessage='Collections are curated lists of accounts to help others discover more of the Fediverse.'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{!withoutAddCollectionButton && (
|
||||||
<Link to='/collections/new' className='button'>
|
<Link to='/collections/new' className='button'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.account_featured_self.no_collections_button'
|
id='empty_column.account_featured_self.no_collections_button'
|
||||||
defaultMessage='Create a collection'
|
defaultMessage='Create a collection'
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
)}
|
||||||
|
<Button secondary onClick={confirmHideFeaturedTab}>
|
||||||
|
<FormattedMessage
|
||||||
|
id='empty_column.account_featured_self.no_collections_hide_tab'
|
||||||
|
defaultMessage='Hide this tab instead'
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -72,7 +104,7 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
message = (
|
message = (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.account_featured_self.pre_collections_desc'
|
id='empty_column.account_featured_self.pre_collections_desc'
|
||||||
defaultMessage='Collections (coming in Mastodon 4.6) allows you to create your own curated lists of accounts to recommend to others.'
|
defaultMessage='Collections (coming in Mastodon 4.6) allow you to create your own curated lists of accounts to recommend to others.'
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -93,49 +125,23 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Standard other account empty state.
|
if (acct) {
|
||||||
title = (
|
title = (
|
||||||
<FormattedMessage
|
|
||||||
id='empty_column.account_featured_other.title'
|
|
||||||
defaultMessage='Nothing to see here'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
if (hasCollections) {
|
|
||||||
if (acct) {
|
|
||||||
message = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='empty_column.account_featured_other.no_collections_desc'
|
|
||||||
defaultMessage='{acct} hasn’t created any collections yet.'
|
|
||||||
values={{ acct }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
message = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='empty_column.account_featured_unknown.no_collections_desc'
|
|
||||||
defaultMessage='This account hasn’t created any collections yet.'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (acct) {
|
|
||||||
message = (
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.account_featured.other'
|
id='empty_column.account_featured.other'
|
||||||
defaultMessage='{acct} hasn’t featured anything yet.'
|
defaultMessage='{acct} has not featured anything yet.'
|
||||||
values={{ acct }}
|
values={{ acct }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
message = (
|
title = (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.account_featured_unknown.other'
|
id='empty_column.account_featured_unknown.other'
|
||||||
defaultMessage='This account hasn’t featured anything yet.'
|
defaultMessage='This account has not featured anything yet.'
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return <EmptyState title={title} message={message} image={image} />;
|
return <EmptyState title={title} message={message} image={image} />;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
.subheading {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
min-height: 52px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
background: var(--color-bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
display: flex;
|
||||||
|
padding-block: 4px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: none;
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: var(--outline-focus-default);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.icon) {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
import type { ComponentPropsWithoutRef } from 'react';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import type { IconProp } from '@/flavours/glitch/components/icon';
|
||||||
|
import { Icon } from '@/flavours/glitch/components/icon';
|
||||||
|
import { polymorphicForwardRef } from '@/types/polymorphic';
|
||||||
|
|
||||||
|
import classes from './subheading.module.scss';
|
||||||
|
|
||||||
|
export const Subheading = polymorphicForwardRef<'h2'>(
|
||||||
|
({ as: Component = 'h2', children, className, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<Component
|
||||||
|
ref={ref}
|
||||||
|
className={classNames(classes.subheading, className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Component>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
interface SubheadingLinkProps extends ComponentPropsWithoutRef<typeof Link> {
|
||||||
|
icon: IconProp;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SubheadingLink: React.FC<SubheadingLinkProps> = ({
|
||||||
|
icon,
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Link className={classNames(classes.link, className)} {...props}>
|
||||||
|
<Icon id='subheading-icon' icon={icon} />
|
||||||
|
{children}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -6,9 +6,10 @@ import { useHistory } from 'react-router';
|
|||||||
|
|
||||||
import { List as ImmutableList } from 'immutable';
|
import { List as ImmutableList } from 'immutable';
|
||||||
|
|
||||||
|
import { AccountListItem } from '@/flavours/glitch/components/account_list_item';
|
||||||
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
|
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
|
||||||
|
import AddIcon from '@/material-icons/400-24px/add.svg?react';
|
||||||
import { fetchEndorsedAccounts } from 'flavours/glitch/actions/accounts';
|
import { fetchEndorsedAccounts } from 'flavours/glitch/actions/accounts';
|
||||||
import { Account } from 'flavours/glitch/components/account';
|
|
||||||
import { ColumnBackButton } from 'flavours/glitch/components/column_back_button';
|
import { ColumnBackButton } from 'flavours/glitch/components/column_back_button';
|
||||||
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import { RemoteHint } from 'flavours/glitch/components/remote_hint';
|
import { RemoteHint } from 'flavours/glitch/components/remote_hint';
|
||||||
@ -28,10 +29,13 @@ import {
|
|||||||
} from 'flavours/glitch/reducers/slices/collections';
|
} from 'flavours/glitch/reducers/slices/collections';
|
||||||
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
|
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
|
||||||
|
|
||||||
import { CollectionListItem } from '../collections/detail/collection_list_item';
|
import { CollectionListItem } from '../collections/components/collection_list_item';
|
||||||
import { areCollectionsEnabled } from '../collections/utils';
|
import { areCollectionsEnabled } from '../collections/utils';
|
||||||
|
|
||||||
import { EmptyMessage } from './components/empty_message';
|
import { EmptyMessage } from './components/empty_message';
|
||||||
|
import { Subheading, SubheadingLink } from './components/subheading';
|
||||||
|
|
||||||
|
const collectionsEnabled = areCollectionsEnabled();
|
||||||
|
|
||||||
const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
||||||
multiColumn,
|
multiColumn,
|
||||||
@ -54,13 +58,12 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
if (accountId) {
|
if (accountId) {
|
||||||
void dispatch(fetchEndorsedAccounts({ accountId }));
|
void dispatch(fetchEndorsedAccounts({ accountId }));
|
||||||
|
|
||||||
if (areCollectionsEnabled()) {
|
if (collectionsEnabled) {
|
||||||
void dispatch(fetchAccountCollections({ accountId }));
|
void dispatch(fetchAccountCollections({ accountId }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [accountId, dispatch]);
|
}, [accountId, dispatch]);
|
||||||
|
|
||||||
const isLoading = !accountId;
|
|
||||||
const featuredAccountIds = useAppSelector(
|
const featuredAccountIds = useAppSelector(
|
||||||
(state) =>
|
(state) =>
|
||||||
state.user_lists.getIn(
|
state.user_lists.getIn(
|
||||||
@ -68,8 +71,8 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
ImmutableList(),
|
ImmutableList(),
|
||||||
) as ImmutableList<string>,
|
) as ImmutableList<string>,
|
||||||
);
|
);
|
||||||
const { collections, status } = useAppSelector((state) =>
|
const { collections, status: collectionsLoadStatus } = useAppSelector(
|
||||||
selectAccountCollections(state, accountId ?? null),
|
(state) => selectAccountCollections(state, accountId ?? null),
|
||||||
);
|
);
|
||||||
const listedCollections = collections.filter(
|
const listedCollections = collections.filter(
|
||||||
// Hide unlisted and empty collections to avoid confusion
|
// Hide unlisted and empty collections to avoid confusion
|
||||||
@ -78,6 +81,15 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
(item) => item.discoverable && !!item.item_count,
|
(item) => item.discoverable && !!item.item_count,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hasCollections =
|
||||||
|
collectionsEnabled &&
|
||||||
|
collectionsLoadStatus === 'idle' &&
|
||||||
|
listedCollections.length > 0;
|
||||||
|
|
||||||
|
const hasFeaturedAccounts = !featuredAccountIds.isEmpty();
|
||||||
|
|
||||||
|
const isLoading = !accountId || collectionsLoadStatus !== 'idle';
|
||||||
|
|
||||||
if (accountId === null) {
|
if (accountId === null) {
|
||||||
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
|
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
|
||||||
}
|
}
|
||||||
@ -92,7 +104,7 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (featuredAccountIds.isEmpty() && listedCollections.length === 0) {
|
if (!hasFeaturedAccounts && !hasCollections) {
|
||||||
return (
|
return (
|
||||||
<AccountFeaturedWrapper accountId={accountId}>
|
<AccountFeaturedWrapper accountId={accountId}>
|
||||||
<EmptyMessage
|
<EmptyMessage
|
||||||
@ -114,14 +126,45 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
{accountId && (
|
{accountId && (
|
||||||
<AccountHeader accountId={accountId} hideTabs={forceEmptyState} />
|
<AccountHeader accountId={accountId} hideTabs={forceEmptyState} />
|
||||||
)}
|
)}
|
||||||
{listedCollections.length > 0 && status === 'idle' && (
|
{!featuredAccountIds.isEmpty() && (
|
||||||
<>
|
<>
|
||||||
<h4 className='column-subheading'>
|
<Subheading as='h2'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='account.featured.accounts'
|
||||||
|
defaultMessage='Profiles'
|
||||||
|
/>
|
||||||
|
</Subheading>
|
||||||
|
<ItemList>
|
||||||
|
{featuredAccountIds.map((featuredAccountId, index) => (
|
||||||
|
<Article
|
||||||
|
focusable
|
||||||
|
key={featuredAccountId}
|
||||||
|
aria-posinset={index + 1}
|
||||||
|
aria-setsize={featuredAccountIds.size}
|
||||||
|
>
|
||||||
|
<AccountListItem accountId={featuredAccountId} />
|
||||||
|
</Article>
|
||||||
|
))}
|
||||||
|
</ItemList>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{collectionsEnabled && (
|
||||||
|
<>
|
||||||
|
<Subheading as='header'>
|
||||||
|
<h2>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='account.featured.collections'
|
id='account.featured.collections'
|
||||||
defaultMessage='Collections'
|
defaultMessage='Collections'
|
||||||
/>
|
/>
|
||||||
</h4>
|
</h2>
|
||||||
|
<SubheadingLink to='/collections/new' icon={AddIcon}>
|
||||||
|
<FormattedMessage
|
||||||
|
id='account.featured.new_collection'
|
||||||
|
defaultMessage='New collection'
|
||||||
|
/>
|
||||||
|
</SubheadingLink>
|
||||||
|
</Subheading>
|
||||||
|
{hasCollections ? (
|
||||||
<ItemList>
|
<ItemList>
|
||||||
{listedCollections.map((item, index) => (
|
{listedCollections.map((item, index) => (
|
||||||
<CollectionListItem
|
<CollectionListItem
|
||||||
@ -134,28 +177,15 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ItemList>
|
</ItemList>
|
||||||
</>
|
) : (
|
||||||
)}
|
<EmptyMessage
|
||||||
{!featuredAccountIds.isEmpty() && (
|
withoutAddCollectionButton
|
||||||
<>
|
blockedBy={blockedBy}
|
||||||
<h4 className='column-subheading'>
|
hidden={hidden}
|
||||||
<FormattedMessage
|
suspended={suspended}
|
||||||
id='account.featured.accounts'
|
accountId={accountId}
|
||||||
defaultMessage='Profiles'
|
|
||||||
/>
|
/>
|
||||||
</h4>
|
)}
|
||||||
<ItemList>
|
|
||||||
{featuredAccountIds.map((featuredAccountId, index) => (
|
|
||||||
<Article
|
|
||||||
focusable
|
|
||||||
key={featuredAccountId}
|
|
||||||
aria-posinset={index + 1}
|
|
||||||
aria-setsize={featuredAccountIds.size}
|
|
||||||
>
|
|
||||||
<Account id={featuredAccountId} />
|
|
||||||
</Article>
|
|
||||||
))}
|
|
||||||
</ItemList>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<RemoteHint accountId={accountId} />
|
<RemoteHint accountId={accountId} />
|
||||||
|
|||||||
@ -8,8 +8,6 @@ import { NavLink } from 'react-router-dom';
|
|||||||
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
|
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
|
||||||
import { useAccountId } from '@/flavours/glitch/hooks/useAccountId';
|
import { useAccountId } from '@/flavours/glitch/hooks/useAccountId';
|
||||||
|
|
||||||
import { areCollectionsEnabled } from '../../collections/utils';
|
|
||||||
|
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
const isActive: Required<NavLinkProps>['isActive'] = (match, location) =>
|
const isActive: Required<NavLinkProps>['isActive'] = (match, location) =>
|
||||||
@ -41,14 +39,7 @@ export const AccountTabs: FC = () => {
|
|||||||
)}
|
)}
|
||||||
{show_featured && (
|
{show_featured && (
|
||||||
<NavLink exact to={`/@${acct}/featured`}>
|
<NavLink exact to={`/@${acct}/featured`}>
|
||||||
{areCollectionsEnabled() ? (
|
|
||||||
<FormattedMessage
|
|
||||||
id='account.featured.collections'
|
|
||||||
defaultMessage='Collections'
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<FormattedMessage id='account.featured' defaultMessage='Featured' />
|
<FormattedMessage id='account.featured' defaultMessage='Featured' />
|
||||||
)}
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
padding: 12px 16px;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
&:not(.wrapperWithoutBorder) {
|
||||||
|
border-bottom: 1px solid var(--color-border-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuButton {
|
||||||
|
padding: 4px;
|
||||||
|
margin-top: -2px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
import { useId } from 'react';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { Article } from 'flavours/glitch/components/scrollable_list/components';
|
||||||
|
import type { CollectionLockupProps } from 'flavours/glitch/features/collections/components/collection_lockup';
|
||||||
|
import { CollectionLockup } from 'flavours/glitch/features/collections/components/collection_lockup';
|
||||||
|
import { CollectionMenu } from 'flavours/glitch/features/collections/components/collection_menu';
|
||||||
|
|
||||||
|
import classes from './collection_list_item.module.scss';
|
||||||
|
|
||||||
|
interface CollectionListItemProps extends CollectionLockupProps {
|
||||||
|
withoutBorder?: boolean;
|
||||||
|
positionInList: number;
|
||||||
|
listSize: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CollectionListItem: React.FC<CollectionListItemProps> = ({
|
||||||
|
collection,
|
||||||
|
withoutBorder,
|
||||||
|
positionInList,
|
||||||
|
listSize,
|
||||||
|
...otherProps
|
||||||
|
}) => {
|
||||||
|
const uniqueId = useId();
|
||||||
|
const linkId = `${uniqueId}-link`;
|
||||||
|
const infoId = `${uniqueId}-info`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Article
|
||||||
|
focusable
|
||||||
|
className={classNames(
|
||||||
|
classes.wrapper,
|
||||||
|
withoutBorder && classes.wrapperWithoutBorder,
|
||||||
|
)}
|
||||||
|
aria-labelledby={linkId}
|
||||||
|
aria-describedby={infoId}
|
||||||
|
aria-posinset={positionInList}
|
||||||
|
aria-setsize={listSize}
|
||||||
|
>
|
||||||
|
<CollectionLockup collection={collection} {...otherProps} />
|
||||||
|
|
||||||
|
<CollectionMenu
|
||||||
|
context='list'
|
||||||
|
collection={collection}
|
||||||
|
className={classes.menuButton}
|
||||||
|
/>
|
||||||
|
</Article>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,21 +1,11 @@
|
|||||||
.wrapper {
|
|
||||||
display: flex;
|
|
||||||
align-items: start;
|
|
||||||
margin-inline: 24px;
|
|
||||||
padding-block: 12px;
|
|
||||||
gap: 16px;
|
|
||||||
|
|
||||||
&:not(.wrapperWithoutBorder) {
|
|
||||||
border-bottom: 1px solid var(--color-border-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
column-gap: 12px;
|
column-gap: 12px;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatarGrid {
|
.avatarGrid {
|
||||||
@ -70,13 +60,3 @@
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuButton {
|
|
||||||
padding: 4px;
|
|
||||||
margin-top: -2px;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
import { useId } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import WarningIcon from '@/material-icons/400-24px/warning.svg?react';
|
||||||
|
import type { ApiCollectionJSON } from 'flavours/glitch/api_types/collections';
|
||||||
|
import { AvatarById } from 'flavours/glitch/components/avatar';
|
||||||
|
import { useAccountHandle } from 'flavours/glitch/components/display_name/default';
|
||||||
|
import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp';
|
||||||
|
import { useAccount } from 'flavours/glitch/hooks/useAccount';
|
||||||
|
import { domain } from 'flavours/glitch/initial_state';
|
||||||
|
|
||||||
|
import classes from './collection_lockup.module.scss';
|
||||||
|
|
||||||
|
export const AvatarGrid: React.FC<{
|
||||||
|
accountIds: (string | undefined)[];
|
||||||
|
sensitive?: boolean;
|
||||||
|
}> = ({ accountIds: ids, sensitive }) => {
|
||||||
|
const avatarIds = [ids[0], ids[1], ids[2], ids[3]];
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
classes.avatarGrid,
|
||||||
|
sensitive ? classes.avatarGridSensitive : null,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{avatarIds.map((id) => (
|
||||||
|
<AvatarById
|
||||||
|
animate={false}
|
||||||
|
key={id}
|
||||||
|
accountId={id}
|
||||||
|
className={classes.avatar}
|
||||||
|
size={25}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{sensitive && <WarningIcon className={classes.avatarSensitiveBadge} />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface CollectionLockupProps {
|
||||||
|
collection: ApiCollectionJSON;
|
||||||
|
withAuthorHandle?: boolean;
|
||||||
|
withTimestamp?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CollectionLockup: React.FC<CollectionLockupProps> = ({
|
||||||
|
collection,
|
||||||
|
withAuthorHandle = true,
|
||||||
|
withTimestamp,
|
||||||
|
}) => {
|
||||||
|
const { id, name } = collection;
|
||||||
|
const uniqueId = useId();
|
||||||
|
const linkId = `${uniqueId}-link`;
|
||||||
|
const infoId = `${uniqueId}-info`;
|
||||||
|
const authorAccount = useAccount(collection.account_id);
|
||||||
|
const authorHandle = useAccountHandle(authorAccount, domain);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.content}>
|
||||||
|
<AvatarGrid
|
||||||
|
accountIds={collection.items.map((item) => item.account_id)}
|
||||||
|
sensitive={collection.sensitive}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<h2 id={linkId}>
|
||||||
|
<Link to={`/collections/${id}`} className={classes.link}>
|
||||||
|
{name}
|
||||||
|
</Link>
|
||||||
|
</h2>
|
||||||
|
<ul className={classes.info} id={infoId}>
|
||||||
|
{collection.sensitive && (
|
||||||
|
<li className='sr-only'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='collections.sensitive'
|
||||||
|
defaultMessage='Sensitive'
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
{withAuthorHandle && authorAccount && (
|
||||||
|
<FormattedMessage
|
||||||
|
id='collections.by_account'
|
||||||
|
defaultMessage='by {account_handle}'
|
||||||
|
values={{
|
||||||
|
account_handle: authorHandle,
|
||||||
|
}}
|
||||||
|
tagName='li'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<FormattedMessage
|
||||||
|
id='collections.account_count'
|
||||||
|
defaultMessage='{count, plural, one {# account} other {# accounts}}'
|
||||||
|
values={{ count: collection.item_count }}
|
||||||
|
tagName='li'
|
||||||
|
/>
|
||||||
|
{withTimestamp && (
|
||||||
|
<FormattedMessage
|
||||||
|
id='collections.last_updated_at'
|
||||||
|
defaultMessage='Last updated: {date}'
|
||||||
|
values={{
|
||||||
|
date: (
|
||||||
|
<RelativeTimestamp timestamp={collection.updated_at} long />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
tagName='li'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
padding: 12px;
|
||||||
|
gap: 12px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid var(--color-border-primary);
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
import type { CollectionLockupProps } from 'flavours/glitch/features/collections/components/collection_lockup';
|
||||||
|
import { CollectionLockup } from 'flavours/glitch/features/collections/components/collection_lockup';
|
||||||
|
|
||||||
|
import classes from './collection_preview_card.module.scss';
|
||||||
|
|
||||||
|
interface CollectionPreviewCardProps extends CollectionLockupProps {
|
||||||
|
onRemove?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CollectionPreviewCard: React.FC<CollectionPreviewCardProps> = ({
|
||||||
|
collection,
|
||||||
|
onRemove,
|
||||||
|
...otherProps
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className={classes.wrapper}>
|
||||||
|
<CollectionLockup collection={collection} {...otherProps} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -5,27 +5,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.preview {
|
.preview {
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap-reverse;
|
|
||||||
align-items: start;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 16px;
|
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
border-radius: 8px;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: linear-gradient(
|
|
||||||
145deg,
|
|
||||||
var(--color-bg-brand-soft),
|
|
||||||
var(--color-bg-primary)
|
|
||||||
);
|
|
||||||
border: 1px solid var(--color-bg-brand-base);
|
|
||||||
}
|
|
||||||
|
|
||||||
.previewHeading {
|
|
||||||
font-size: 22px;
|
|
||||||
line-height: 1.3;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
@ -8,8 +8,6 @@ import { me } from '@/flavours/glitch/initial_state';
|
|||||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||||
import { changeCompose, focusCompose } from 'flavours/glitch/actions/compose';
|
import { changeCompose, focusCompose } from 'flavours/glitch/actions/compose';
|
||||||
import type { ApiCollectionJSON } from 'flavours/glitch/api_types/collections';
|
import type { ApiCollectionJSON } from 'flavours/glitch/api_types/collections';
|
||||||
import { AvatarById } from 'flavours/glitch/components/avatar';
|
|
||||||
import { AvatarGroup } from 'flavours/glitch/components/avatar_group';
|
|
||||||
import { Button } from 'flavours/glitch/components/button';
|
import { Button } from 'flavours/glitch/components/button';
|
||||||
import { CopyLinkField } from 'flavours/glitch/components/form_fields';
|
import { CopyLinkField } from 'flavours/glitch/components/form_fields';
|
||||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
@ -20,7 +18,7 @@ import {
|
|||||||
} from 'flavours/glitch/components/modal_shell';
|
} from 'flavours/glitch/components/modal_shell';
|
||||||
import { useAppDispatch } from 'flavours/glitch/store';
|
import { useAppDispatch } from 'flavours/glitch/store';
|
||||||
|
|
||||||
import { AuthorNote } from '.';
|
import { CollectionPreviewCard } from './collection_preview_card';
|
||||||
import classes from './share_modal.module.scss';
|
import classes from './share_modal.module.scss';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
@ -95,24 +93,13 @@ export const CollectionShareModal: React.FC<{
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={classes.preview}>
|
<div className={classes.preview}>
|
||||||
<div>
|
<CollectionPreviewCard collection={collection} />
|
||||||
<h2 className={classes.previewHeading}>{collection.name}</h2>
|
|
||||||
<AuthorNote id={collection.account_id} />
|
|
||||||
</div>
|
|
||||||
<AvatarGroup>
|
|
||||||
{collection.items.slice(0, 5).map(({ account_id }) => {
|
|
||||||
if (!account_id) return;
|
|
||||||
return (
|
|
||||||
<AvatarById key={account_id} accountId={account_id} size={28} />
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</AvatarGroup>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CopyLinkField
|
<CopyLinkField
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
id: 'collection.share_modal.share_link_label',
|
id: 'collection.share_modal.share_link_label',
|
||||||
defaultMessage: 'Invite share link',
|
defaultMessage: 'Share link',
|
||||||
})}
|
})}
|
||||||
value={collectionLink}
|
value={collectionLink}
|
||||||
/>
|
/>
|
||||||
@ -146,7 +146,6 @@ export const CollectionAccountsList: React.FC<{
|
|||||||
<AccountListItem
|
<AccountListItem
|
||||||
accountId={account_id}
|
accountId={account_id}
|
||||||
withBorder={index !== items.length - 1}
|
withBorder={index !== items.length - 1}
|
||||||
stats={['followers', 'last-active']}
|
|
||||||
renderButton={renderAccountItemButton}
|
renderButton={renderAccountItemButton}
|
||||||
/>
|
/>
|
||||||
</Article>
|
</Article>
|
||||||
|
|||||||
@ -1,139 +0,0 @@
|
|||||||
import { useId } from 'react';
|
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
|
|
||||||
import WarningIcon from '@/material-icons/400-24px/warning.svg?react';
|
|
||||||
import type { ApiCollectionJSON } from 'flavours/glitch/api_types/collections';
|
|
||||||
import { AvatarById } from 'flavours/glitch/components/avatar';
|
|
||||||
import { useAccountHandle } from 'flavours/glitch/components/display_name/default';
|
|
||||||
import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp';
|
|
||||||
import { Article } from 'flavours/glitch/components/scrollable_list/components';
|
|
||||||
import { useAccount } from 'flavours/glitch/hooks/useAccount';
|
|
||||||
import { domain } from 'flavours/glitch/initial_state';
|
|
||||||
|
|
||||||
import classes from './collection_list_item.module.scss';
|
|
||||||
import { CollectionMenu } from './collection_menu';
|
|
||||||
|
|
||||||
export const AvatarGrid: React.FC<{
|
|
||||||
accountIds: (string | undefined)[];
|
|
||||||
sensitive?: boolean;
|
|
||||||
}> = ({ accountIds: ids, sensitive }) => {
|
|
||||||
const avatarIds = [ids[0], ids[1], ids[2], ids[3]];
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
classes.avatarGrid,
|
|
||||||
sensitive ? classes.avatarGridSensitive : null,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{avatarIds.map((id) => (
|
|
||||||
<AvatarById
|
|
||||||
animate={false}
|
|
||||||
key={id}
|
|
||||||
accountId={id}
|
|
||||||
className={classes.avatar}
|
|
||||||
size={25}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
{sensitive && <WarningIcon className={classes.avatarSensitiveBadge} />}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CollectionListItem: React.FC<{
|
|
||||||
collection: ApiCollectionJSON;
|
|
||||||
withoutBorder?: boolean;
|
|
||||||
withAuthorHandle?: boolean;
|
|
||||||
withTimestamp?: boolean;
|
|
||||||
positionInList: number;
|
|
||||||
listSize: number;
|
|
||||||
}> = ({
|
|
||||||
collection,
|
|
||||||
withoutBorder,
|
|
||||||
withAuthorHandle = true,
|
|
||||||
withTimestamp,
|
|
||||||
positionInList,
|
|
||||||
listSize,
|
|
||||||
}) => {
|
|
||||||
const { id, name } = collection;
|
|
||||||
const uniqueId = useId();
|
|
||||||
const linkId = `${uniqueId}-link`;
|
|
||||||
const infoId = `${uniqueId}-info`;
|
|
||||||
const authorAccount = useAccount(collection.account_id);
|
|
||||||
const authorHandle = useAccountHandle(authorAccount, domain);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Article
|
|
||||||
focusable
|
|
||||||
className={classNames(
|
|
||||||
classes.wrapper,
|
|
||||||
withoutBorder && classes.wrapperWithoutBorder,
|
|
||||||
)}
|
|
||||||
aria-labelledby={linkId}
|
|
||||||
aria-describedby={infoId}
|
|
||||||
aria-posinset={positionInList}
|
|
||||||
aria-setsize={listSize}
|
|
||||||
>
|
|
||||||
<div className={classes.content}>
|
|
||||||
<AvatarGrid
|
|
||||||
accountIds={collection.items.map((item) => item.account_id)}
|
|
||||||
sensitive={collection.sensitive}
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<h2 id={linkId}>
|
|
||||||
<Link to={`/collections/${id}`} className={classes.link}>
|
|
||||||
{name}
|
|
||||||
</Link>
|
|
||||||
</h2>
|
|
||||||
<ul className={classes.info} id={infoId}>
|
|
||||||
{collection.sensitive && (
|
|
||||||
<li className='sr-only'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='collections.sensitive'
|
|
||||||
defaultMessage='Sensitive'
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
)}
|
|
||||||
{withAuthorHandle && authorAccount && (
|
|
||||||
<FormattedMessage
|
|
||||||
id='collections.by_account'
|
|
||||||
defaultMessage='by {account_handle}'
|
|
||||||
values={{
|
|
||||||
account_handle: authorHandle,
|
|
||||||
}}
|
|
||||||
tagName='li'
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<FormattedMessage
|
|
||||||
id='collections.account_count'
|
|
||||||
defaultMessage='{count, plural, one {# account} other {# accounts}}'
|
|
||||||
values={{ count: collection.item_count }}
|
|
||||||
tagName='li'
|
|
||||||
/>
|
|
||||||
{withTimestamp && (
|
|
||||||
<FormattedMessage
|
|
||||||
id='collections.last_updated_at'
|
|
||||||
defaultMessage='Last updated: {date}'
|
|
||||||
values={{
|
|
||||||
date: (
|
|
||||||
<RelativeTimestamp timestamp={collection.updated_at} long />
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
tagName='li'
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<CollectionMenu
|
|
||||||
context='list'
|
|
||||||
collection={collection}
|
|
||||||
className={classes.menuButton}
|
|
||||||
/>
|
|
||||||
</Article>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -23,8 +23,9 @@ import { domain, me } from 'flavours/glitch/initial_state';
|
|||||||
import { fetchCollection } from 'flavours/glitch/reducers/slices/collections';
|
import { fetchCollection } from 'flavours/glitch/reducers/slices/collections';
|
||||||
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
|
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
|
||||||
|
|
||||||
|
import { CollectionMenu } from '../components/collection_menu';
|
||||||
|
|
||||||
import { CollectionAccountsList } from './accounts_list';
|
import { CollectionAccountsList } from './accounts_list';
|
||||||
import { CollectionMenu } from './collection_menu';
|
|
||||||
import { useConfirmRevoke } from './revoke_collection_inclusion_modal';
|
import { useConfirmRevoke } from './revoke_collection_inclusion_modal';
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ export const AuthorNote: React.FC<{ id: string }> = ({ id }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RevokeControls: React.FC<{
|
const RevokeControls: React.FC<{
|
||||||
collection: ApiCollectionJSON;
|
collection: ApiCollectionJSON;
|
||||||
}> = ({ collection }) => {
|
}> = ({ collection }) => {
|
||||||
const authorAccount = useAccount(collection.account_id);
|
const authorAccount = useAccount(collection.account_id);
|
||||||
|
|||||||
@ -61,9 +61,11 @@ const AddedAccountItem: React.FC<{
|
|||||||
onRemove(accountId);
|
onRemove(accountId);
|
||||||
}, [accountId, onRemove]);
|
}, [accountId, onRemove]);
|
||||||
|
|
||||||
|
const lastStatusAt = account?.last_status_at;
|
||||||
|
|
||||||
const lastPostHint = useMemo(
|
const lastPostHint = useMemo(
|
||||||
() =>
|
() =>
|
||||||
isOlderThanAWeek(account?.last_status_at) && (
|
(!lastStatusAt || isOlderThanAWeek(lastStatusAt)) && (
|
||||||
<Badge
|
<Badge
|
||||||
label={
|
label={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
@ -75,7 +77,7 @@ const AddedAccountItem: React.FC<{
|
|||||||
className={classes.accountBadge}
|
className={classes.accountBadge}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[account?.last_status_at],
|
[lastStatusAt],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -10,22 +10,32 @@ import CollectionsFilledIcon from '@/material-icons/400-24px/category-fill.svg?r
|
|||||||
import SquigglyArrow from '@/svg-icons/squiggly_arrow.svg?react';
|
import SquigglyArrow from '@/svg-icons/squiggly_arrow.svg?react';
|
||||||
import { Column } from 'flavours/glitch/components/column';
|
import { Column } from 'flavours/glitch/components/column';
|
||||||
import { ColumnHeader } from 'flavours/glitch/components/column_header';
|
import { ColumnHeader } from 'flavours/glitch/components/column_header';
|
||||||
|
import { DisplayNameSimple } from 'flavours/glitch/components/display_name/simple';
|
||||||
import { Icon } from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import {
|
import {
|
||||||
ItemList,
|
ItemList,
|
||||||
Scrollable,
|
Scrollable,
|
||||||
} from 'flavours/glitch/components/scrollable_list/components';
|
} from 'flavours/glitch/components/scrollable_list/components';
|
||||||
|
import { useAccount } from 'flavours/glitch/hooks/useAccount';
|
||||||
|
import {
|
||||||
|
useAccountId,
|
||||||
|
useCurrentAccountId,
|
||||||
|
} from 'flavours/glitch/hooks/useAccountId';
|
||||||
import {
|
import {
|
||||||
fetchAccountCollections,
|
fetchAccountCollections,
|
||||||
selectAccountCollections,
|
selectAccountCollections,
|
||||||
} from 'flavours/glitch/reducers/slices/collections';
|
} from 'flavours/glitch/reducers/slices/collections';
|
||||||
import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
|
import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
|
||||||
|
|
||||||
import { CollectionListItem } from './detail/collection_list_item';
|
import { CollectionListItem } from './components/collection_list_item';
|
||||||
import { messages as editorMessages } from './editor';
|
import { messages as editorMessages } from './editor';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
heading: { id: 'column.collections', defaultMessage: 'My collections' },
|
headingMe: { id: 'column.my_collections', defaultMessage: 'My collections' },
|
||||||
|
headingOther: {
|
||||||
|
id: 'column.other_collections',
|
||||||
|
defaultMessage: 'Collections by {name}',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const Collections: React.FC<{
|
export const Collections: React.FC<{
|
||||||
@ -33,17 +43,22 @@ export const Collections: React.FC<{
|
|||||||
}> = ({ multiColumn }) => {
|
}> = ({ multiColumn }) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const me = useAppSelector((state) => state.meta.get('me') as string);
|
const me = useCurrentAccountId();
|
||||||
|
const accountId = useAccountId();
|
||||||
|
const account = useAccount(accountId);
|
||||||
|
|
||||||
const { collections, status } = useAppSelector((state) =>
|
const { collections, status } = useAppSelector((state) =>
|
||||||
selectAccountCollections(state, me),
|
selectAccountCollections(state, accountId),
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void dispatch(fetchAccountCollections({ accountId: me }));
|
if (accountId) {
|
||||||
}, [dispatch, me]);
|
void dispatch(fetchAccountCollections({ accountId }));
|
||||||
|
}
|
||||||
|
}, [dispatch, accountId]);
|
||||||
|
|
||||||
const emptyMessage =
|
const emptyMessage =
|
||||||
status === 'error' ? (
|
status === 'error' || !accountId ? (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='collections.error_loading_collections'
|
id='collections.error_loading_collections'
|
||||||
defaultMessage='There was an error when trying to load your collections.'
|
defaultMessage='There was an error when trying to load your collections.'
|
||||||
@ -67,17 +82,27 @@ export const Collections: React.FC<{
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isOwnCollection = accountId === me;
|
||||||
|
const titleMessage = isOwnCollection
|
||||||
|
? messages.headingMe
|
||||||
|
: messages.headingOther;
|
||||||
|
|
||||||
|
const pageTitle = intl.formatMessage(titleMessage, {
|
||||||
|
name: account?.get('display_name'),
|
||||||
|
});
|
||||||
|
const pageTitleHtml = intl.formatMessage(titleMessage, {
|
||||||
|
name: <DisplayNameSimple account={account} />,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column
|
<Column bindToDocument={!multiColumn} label={pageTitle}>
|
||||||
bindToDocument={!multiColumn}
|
|
||||||
label={intl.formatMessage(messages.heading)}
|
|
||||||
>
|
|
||||||
<ColumnHeader
|
<ColumnHeader
|
||||||
title={intl.formatMessage(messages.heading)}
|
title={pageTitleHtml}
|
||||||
icon='collections'
|
icon='collections'
|
||||||
iconComponent={CollectionsFilledIcon}
|
iconComponent={CollectionsFilledIcon}
|
||||||
multiColumn={multiColumn}
|
multiColumn={multiColumn}
|
||||||
extraButton={
|
extraButton={
|
||||||
|
isOwnCollection && (
|
||||||
<Link
|
<Link
|
||||||
to='/collections/new'
|
to='/collections/new'
|
||||||
className='column-header__button'
|
className='column-header__button'
|
||||||
@ -86,6 +111,7 @@ export const Collections: React.FC<{
|
|||||||
>
|
>
|
||||||
<Icon id='plus' icon={AddIcon} />
|
<Icon id='plus' icon={AddIcon} />
|
||||||
</Link>
|
</Link>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -105,7 +131,7 @@ export const Collections: React.FC<{
|
|||||||
</Scrollable>
|
</Scrollable>
|
||||||
|
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{intl.formatMessage(messages.heading)}</title>
|
<title>{pageTitle}</title>
|
||||||
<meta name='robots' content='noindex' />
|
<meta name='robots' content='noindex' />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
</Column>
|
</Column>
|
||||||
|
|||||||
@ -55,12 +55,20 @@ export const AccountList: FC<AccountListProps> = ({
|
|||||||
}
|
}
|
||||||
const children =
|
const children =
|
||||||
list?.items.map((followerId) => (
|
list?.items.map((followerId) => (
|
||||||
<AccountListItem key={followerId} accountId={followerId} />
|
<AccountListItem
|
||||||
|
key={followerId}
|
||||||
|
accountId={followerId}
|
||||||
|
withBio={false}
|
||||||
|
/>
|
||||||
)) ?? [];
|
)) ?? [];
|
||||||
|
|
||||||
if (prependAccountId) {
|
if (prependAccountId) {
|
||||||
children.unshift(
|
children.unshift(
|
||||||
<AccountListItem key={prependAccountId} accountId={prependAccountId} />,
|
<AccountListItem
|
||||||
|
key={prependAccountId}
|
||||||
|
accountId={prependAccountId}
|
||||||
|
withBio={false}
|
||||||
|
/>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return children;
|
return children;
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import type { Map as ImmutableMap } from 'immutable';
|
|||||||
import { animated, useSpring } from '@react-spring/web';
|
import { animated, useSpring } from '@react-spring/web';
|
||||||
import { useDrag } from '@use-gesture/react';
|
import { useDrag } from '@use-gesture/react';
|
||||||
|
|
||||||
|
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
|
||||||
import AddIcon from '@/material-icons/400-24px/add.svg?react';
|
import AddIcon from '@/material-icons/400-24px/add.svg?react';
|
||||||
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
||||||
import BookmarksActiveIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react';
|
import BookmarksActiveIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react';
|
||||||
@ -226,6 +227,7 @@ export const NavigationPanel: React.FC<{ multiColumn?: boolean }> = ({
|
|||||||
const { signedIn, permissions, disabledAccountId } = useIdentity();
|
const { signedIn, permissions, disabledAccountId } = useIdentity();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const showSearch = useBreakpoint('full') && !multiColumn;
|
const showSearch = useBreakpoint('full') && !multiColumn;
|
||||||
|
const account = useAccount(me);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
let banner: React.ReactNode;
|
let banner: React.ReactNode;
|
||||||
@ -361,7 +363,7 @@ export const NavigationPanel: React.FC<{ multiColumn?: boolean }> = ({
|
|||||||
{areCollectionsEnabled() && (
|
{areCollectionsEnabled() && (
|
||||||
<ColumnLink
|
<ColumnLink
|
||||||
transparent
|
transparent
|
||||||
to='/collections'
|
to={`/@${account?.acct}/collections`}
|
||||||
icon='collections'
|
icon='collections'
|
||||||
iconComponent={CollectionsIcon}
|
iconComponent={CollectionsIcon}
|
||||||
activeIconComponent={CollectionsActiveIcon}
|
activeIconComponent={CollectionsActiveIcon}
|
||||||
|
|||||||
@ -0,0 +1,69 @@
|
|||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { DisplayNameSimple } from '@/flavours/glitch/components/display_name/simple';
|
||||||
|
import { Icon } from '@/flavours/glitch/components/icon';
|
||||||
|
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
|
||||||
|
import CollectionsFilledIcon from '@/material-icons/400-24px/category-fill.svg?react';
|
||||||
|
import type {
|
||||||
|
NotificationGroupAddedToCollection,
|
||||||
|
NotificationGroupCollectionUpdate,
|
||||||
|
} from 'flavours/glitch/models/notification_group';
|
||||||
|
|
||||||
|
import { CollectionPreviewCard } from '../../collections/components/collection_preview_card';
|
||||||
|
|
||||||
|
export const NotificationCollection: React.FC<{
|
||||||
|
notification:
|
||||||
|
| NotificationGroupAddedToCollection
|
||||||
|
| NotificationGroupCollectionUpdate;
|
||||||
|
unread: boolean;
|
||||||
|
}> = ({ notification, unread }) => {
|
||||||
|
const { collection, type } = notification;
|
||||||
|
const collectionCreatorAccount = useAccount(collection.account_id);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'notification-group',
|
||||||
|
`notification-group--${type}`,
|
||||||
|
{ 'notification-group--unread': unread },
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className='notification-group__icon'>
|
||||||
|
<Icon id='collection' icon={CollectionsFilledIcon} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='notification-group__main'>
|
||||||
|
<div className='notification-group__main__header'>
|
||||||
|
<div className='notification-group__main__header__label'>
|
||||||
|
{type === 'added_to_collection' && (
|
||||||
|
<FormattedMessage
|
||||||
|
id='notification.added_to_collection'
|
||||||
|
defaultMessage='{name} added you to a collection'
|
||||||
|
values={{
|
||||||
|
name: (
|
||||||
|
<DisplayNameSimple account={collectionCreatorAccount} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{type === 'collection_update' && (
|
||||||
|
<FormattedMessage
|
||||||
|
id='notification.collection_update'
|
||||||
|
defaultMessage='{name} edited a collection you’re in'
|
||||||
|
values={{
|
||||||
|
name: (
|
||||||
|
<DisplayNameSimple account={collectionCreatorAccount} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CollectionPreviewCard collection={collection} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -9,6 +9,7 @@ import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
|
|||||||
import { NotificationAdminReport } from './notification_admin_report';
|
import { NotificationAdminReport } from './notification_admin_report';
|
||||||
import { NotificationAdminSignUp } from './notification_admin_sign_up';
|
import { NotificationAdminSignUp } from './notification_admin_sign_up';
|
||||||
import { NotificationAnnualReport } from './notification_annual_report';
|
import { NotificationAnnualReport } from './notification_annual_report';
|
||||||
|
import { NotificationCollection } from './notification_collection';
|
||||||
import { NotificationFavourite } from './notification_favourite';
|
import { NotificationFavourite } from './notification_favourite';
|
||||||
import { NotificationFollow } from './notification_follow';
|
import { NotificationFollow } from './notification_follow';
|
||||||
import { NotificationFollowRequest } from './notification_follow_request';
|
import { NotificationFollowRequest } from './notification_follow_request';
|
||||||
@ -156,6 +157,15 @@ export const NotificationGroup: React.FC<{
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 'added_to_collection':
|
||||||
|
case 'collection_update':
|
||||||
|
content = (
|
||||||
|
<NotificationCollection
|
||||||
|
unread={unread}
|
||||||
|
notification={notificationGroup}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
const ColumnSubheading = ({ text }) => {
|
|
||||||
return (
|
|
||||||
<div className='column-subheading'>
|
|
||||||
{text}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
ColumnSubheading.propTypes = {
|
|
||||||
text: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ColumnSubheading;
|
|
||||||
@ -4,6 +4,8 @@ import { defineMessages, useIntl } from 'react-intl';
|
|||||||
|
|
||||||
import { useHistory } from 'react-router';
|
import { useHistory } from 'react-router';
|
||||||
|
|
||||||
|
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
|
||||||
|
import { me } from '@/flavours/glitch/initial_state';
|
||||||
import { deleteCollection } from 'flavours/glitch/reducers/slices/collections';
|
import { deleteCollection } from 'flavours/glitch/reducers/slices/collections';
|
||||||
import { useAppDispatch } from 'flavours/glitch/store';
|
import { useAppDispatch } from 'flavours/glitch/store';
|
||||||
|
|
||||||
@ -34,11 +36,12 @@ export const ConfirmDeleteCollectionModal: React.FC<
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const { acct: currentUserName } = useAccount(me) ?? {};
|
||||||
|
|
||||||
const onConfirm = useCallback(() => {
|
const onConfirm = useCallback(() => {
|
||||||
void dispatch(deleteCollection({ collectionId: id }));
|
void dispatch(deleteCollection({ collectionId: id }));
|
||||||
history.push('/collections');
|
history.push(`/@${currentUserName}/collections`);
|
||||||
}, [dispatch, history, id]);
|
}, [dispatch, history, id, currentUserName]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
|
|||||||
@ -0,0 +1,73 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import { useHistory } from 'react-router';
|
||||||
|
|
||||||
|
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
|
||||||
|
import { useCurrentAccountId } from '@/flavours/glitch/hooks/useAccountId';
|
||||||
|
import { domain } from '@/flavours/glitch/initial_state';
|
||||||
|
import { patchProfile } from '@/flavours/glitch/reducers/slices/profile_edit';
|
||||||
|
import { useAppDispatch } from 'flavours/glitch/store';
|
||||||
|
|
||||||
|
import type { BaseConfirmationModalProps } from './confirmation_modal';
|
||||||
|
import { ConfirmationModal } from './confirmation_modal';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
title: {
|
||||||
|
id: 'confirmations.hide_featured_tab.title',
|
||||||
|
defaultMessage: 'Hide "Featured" tab?',
|
||||||
|
},
|
||||||
|
intro: {
|
||||||
|
id: 'confirmations.hide_featured_tab.intro',
|
||||||
|
defaultMessage:
|
||||||
|
'You can change this at any time under <i>Edit profile > Profile tab settings</i>.',
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
id: 'confirmations.hide_featured_tab.message',
|
||||||
|
defaultMessage:
|
||||||
|
'This will hide the tab for users on {serverName} and other servers running the latest version of Mastodon. Other displays may vary.',
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
id: 'confirmations.hide_featured_tab.confirm',
|
||||||
|
defaultMessage: 'Hide tab',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ConfirmHideFeaturedTabModal: React.FC<
|
||||||
|
BaseConfirmationModalProps
|
||||||
|
> = ({ onClose }) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const history = useHistory();
|
||||||
|
const currentAccountId = useCurrentAccountId();
|
||||||
|
const { acct: currentUserName } = useAccount(currentAccountId) ?? {};
|
||||||
|
|
||||||
|
const onConfirm = useCallback(() => {
|
||||||
|
void dispatch(patchProfile({ show_featured: false }));
|
||||||
|
history.push(`/@${currentUserName}`);
|
||||||
|
}, [currentUserName, dispatch, history]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmationModal
|
||||||
|
title={intl.formatMessage(messages.title)}
|
||||||
|
extraContent={
|
||||||
|
<div className='prose'>
|
||||||
|
<p>
|
||||||
|
{intl.formatMessage(messages.intro, {
|
||||||
|
i: (words) => <i>{words}</i>,
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{intl.formatMessage(messages.message, {
|
||||||
|
serverName: domain,
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
confirm={intl.formatMessage(messages.confirm)}
|
||||||
|
onConfirm={onConfirm}
|
||||||
|
onClose={onClose}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -85,7 +85,7 @@ export const MODAL_COMPONENTS = {
|
|||||||
'DOMAIN_BLOCK': DomainBlockModal,
|
'DOMAIN_BLOCK': DomainBlockModal,
|
||||||
'REPORT': ReportModal,
|
'REPORT': ReportModal,
|
||||||
'REPORT_COLLECTION': ReportCollectionModal,
|
'REPORT_COLLECTION': ReportCollectionModal,
|
||||||
'SHARE_COLLECTION': () => import('@/flavours/glitch/features/collections/detail/share_modal').then(module => ({ default: module.CollectionShareModal })),
|
'SHARE_COLLECTION': () => import('@/flavours/glitch/features/collections/components/share_modal').then(module => ({ default: module.CollectionShareModal })),
|
||||||
'REVOKE_COLLECTION_INCLUSION': () => import('@/flavours/glitch/features/collections/detail/revoke_collection_inclusion_modal').then(module => ({ default: module.RevokeCollectionInclusionModal })),
|
'REVOKE_COLLECTION_INCLUSION': () => import('@/flavours/glitch/features/collections/detail/revoke_collection_inclusion_modal').then(module => ({ default: module.RevokeCollectionInclusionModal })),
|
||||||
'SETTINGS': SettingsModal,
|
'SETTINGS': SettingsModal,
|
||||||
'DEPRECATED_SETTINGS': () => Promise.resolve({ default: DeprecatedSettingsModal }),
|
'DEPRECATED_SETTINGS': () => Promise.resolve({ default: DeprecatedSettingsModal }),
|
||||||
@ -113,6 +113,7 @@ export const MODAL_COMPONENTS = {
|
|||||||
'ACCOUNT_EDIT_IMAGE_ALT': accountEditModal('ImageAltModal'),
|
'ACCOUNT_EDIT_IMAGE_ALT': accountEditModal('ImageAltModal'),
|
||||||
'ACCOUNT_EDIT_IMAGE_DELETE': accountEditModal('ImageDeleteModal'),
|
'ACCOUNT_EDIT_IMAGE_DELETE': accountEditModal('ImageDeleteModal'),
|
||||||
'ACCOUNT_EDIT_IMAGE_UPLOAD': accountEditModal('ImageUploadModal'),
|
'ACCOUNT_EDIT_IMAGE_UPLOAD': accountEditModal('ImageUploadModal'),
|
||||||
|
'ACCOUNT_HIDE_FEATURED_TAB': () => import('@/flavours/glitch/features/ui/components/confirmation_modals/hide_featured_tab').then(module => ({ default: module.ConfirmHideFeaturedTabModal })),
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @arg {keyof import('@/flavours/glitch/features/account_edit/modals')} type */
|
/** @arg {keyof import('@/flavours/glitch/features/account_edit/modals')} type */
|
||||||
|
|||||||
@ -240,6 +240,13 @@ class SwitchingColumnsArea extends PureComponent {
|
|||||||
|
|
||||||
<WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} />
|
<WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} />
|
||||||
<WrappedRoute path={['/@:acct/featured', '/accounts/:id/featured']} component={AccountFeatured} content={children} />
|
<WrappedRoute path={['/@:acct/featured', '/accounts/:id/featured']} component={AccountFeatured} content={children} />
|
||||||
|
{areCollectionsEnabled() &&
|
||||||
|
[
|
||||||
|
<WrappedRoute path={['/@:acct/collections']} component={Collections} content={children} key='collections-list' />,
|
||||||
|
<WrappedRoute path={['/collections/new', '/collections/:id/edit']} component={CollectionsEditor} content={children} key='collections-editor' />,
|
||||||
|
<WrappedRoute path='/collections/:id' component={CollectionDetail} content={children} key='collections-detail' />,
|
||||||
|
]
|
||||||
|
}
|
||||||
<WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} />
|
<WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} />
|
||||||
<WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />
|
<WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />
|
||||||
<WrappedRoute path={['/accounts/:id/followers', '/users/:acct/followers', '/@:acct/followers']} component={Followers} content={children} />
|
<WrappedRoute path={['/accounts/:id/followers', '/users/:acct/followers', '/@:acct/followers']} component={Followers} content={children} />
|
||||||
@ -263,13 +270,6 @@ class SwitchingColumnsArea extends PureComponent {
|
|||||||
<WrappedRoute path='/followed_tags' component={FollowedTags} content={children} />
|
<WrappedRoute path='/followed_tags' component={FollowedTags} content={children} />
|
||||||
<WrappedRoute path='/mutes' component={Mutes} content={children} />
|
<WrappedRoute path='/mutes' component={Mutes} content={children} />
|
||||||
<WrappedRoute path='/lists' component={Lists} content={children} />
|
<WrappedRoute path='/lists' component={Lists} content={children} />
|
||||||
{areCollectionsEnabled() &&
|
|
||||||
[
|
|
||||||
<WrappedRoute path={['/collections/new', '/collections/:id/edit']} component={CollectionsEditor} content={children} key='collections-editor' />,
|
|
||||||
<WrappedRoute path='/collections/:id' component={CollectionDetail} content={children} key='collections-detail' />,
|
|
||||||
<WrappedRoute path='/collections' component={Collections} content={children} key='collections-list' />
|
|
||||||
]
|
|
||||||
}
|
|
||||||
<Route component={BundleColumnError} />
|
<Route component={BundleColumnError} />
|
||||||
</WrappedSwitch>
|
</WrappedSwitch>
|
||||||
</ColumnsArea>
|
</ColumnsArea>
|
||||||
|
|||||||
@ -311,7 +311,7 @@ interface AccountCollectionQuery {
|
|||||||
|
|
||||||
export const selectAccountCollections = createAppSelector(
|
export const selectAccountCollections = createAppSelector(
|
||||||
[
|
[
|
||||||
(_, accountId: string | null) => accountId,
|
(_, accountId?: string | null) => accountId,
|
||||||
(state) => state.collections.accountCollections,
|
(state) => state.collections.accountCollections,
|
||||||
(state) => state.collections.collections,
|
(state) => state.collections.collections,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -4170,15 +4170,6 @@ a.account__display-name {
|
|||||||
margin: -6px 10px;
|
margin: -6px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.column-subheading {
|
|
||||||
background: var(--color-bg-secondary);
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
padding: 12px 24px;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
.getting-started__wrapper {
|
.getting-started__wrapper {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
@use 'variables' as *;
|
@use 'variables' as *;
|
||||||
|
|
||||||
.modal-layout {
|
.modal-layout {
|
||||||
background: var(--color-bg-brand-softest);
|
background: var(--color-bg-primary);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
@ -37,6 +37,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.with-zig-zag-decoration {
|
.with-zig-zag-decoration {
|
||||||
|
isolation: isolate;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@ -53,7 +53,7 @@ export interface BaseApiAccountJSON {
|
|||||||
header_static: string;
|
header_static: string;
|
||||||
header_description: string;
|
header_description: string;
|
||||||
id: string;
|
id: string;
|
||||||
last_status_at: string;
|
last_status_at: string | null;
|
||||||
locked: boolean;
|
locked: boolean;
|
||||||
show_media: boolean;
|
show_media: boolean;
|
||||||
show_media_replies: boolean;
|
show_media_replies: boolean;
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import { useRelationship } from 'mastodon/hooks/useRelationship';
|
|||||||
import type { Relationship } from 'mastodon/models/relationship';
|
import type { Relationship } from 'mastodon/models/relationship';
|
||||||
|
|
||||||
import { EmojiHTML } from '../emoji/html';
|
import { EmojiHTML } from '../emoji/html';
|
||||||
import { FamiliarFollowers } from '../familiar_followers';
|
|
||||||
import { FollowButton } from '../follow_button';
|
import { FollowButton } from '../follow_button';
|
||||||
import { FormattedDateWrapper } from '../formatted_date';
|
import { FormattedDateWrapper } from '../formatted_date';
|
||||||
import { NumberFields, NumberFieldsItem } from '../number_fields';
|
import { NumberFields, NumberFieldsItem } from '../number_fields';
|
||||||
@ -31,10 +30,11 @@ interface Props {
|
|||||||
accountId: string | undefined;
|
accountId: string | undefined;
|
||||||
stats?: Stat[];
|
stats?: Stat[];
|
||||||
renderButton?: (options: RenderButtonOptions) => React.ReactNode;
|
renderButton?: (options: RenderButtonOptions) => React.ReactNode;
|
||||||
|
withBio?: boolean;
|
||||||
withBorder?: boolean;
|
withBorder?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_STATS: Stat[] = ['followers', 'following', 'joined'];
|
const DEFAULT_STATS: Stat[] = ['followers', 'posts', 'last-active'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extended account list item with bio, verified link badge,
|
* Extended account list item with bio, verified link badge,
|
||||||
@ -46,6 +46,7 @@ const DEFAULT_STATS: Stat[] = ['followers', 'following', 'joined'];
|
|||||||
export const AccountListItem: React.FC<Props> = ({
|
export const AccountListItem: React.FC<Props> = ({
|
||||||
accountId,
|
accountId,
|
||||||
stats = DEFAULT_STATS,
|
stats = DEFAULT_STATS,
|
||||||
|
withBio = true,
|
||||||
withBorder = true,
|
withBorder = true,
|
||||||
renderButton = defaultRenderButton,
|
renderButton = defaultRenderButton,
|
||||||
}) => {
|
}) => {
|
||||||
@ -147,11 +148,15 @@ export const AccountListItem: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{account.last_status_at ? (
|
||||||
<RelativeTimestamp
|
<RelativeTimestamp
|
||||||
long
|
long
|
||||||
timestamp={account.last_status_at}
|
timestamp={account.last_status_at}
|
||||||
noFuture
|
noFuture
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
'-'
|
||||||
|
)}
|
||||||
</NumberFieldsItem>
|
</NumberFieldsItem>
|
||||||
)}
|
)}
|
||||||
{firstVerifiedField && (
|
{firstVerifiedField && (
|
||||||
@ -161,8 +166,7 @@ export const AccountListItem: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</NumberFields>
|
</NumberFields>
|
||||||
<FamiliarFollowers accountId={accountId} />
|
{withBio && account.note.length > 0 && (
|
||||||
{account.note.length > 0 && (
|
|
||||||
<EmojiHTML
|
<EmojiHTML
|
||||||
className={classNames(classes.bio, 'translate')}
|
className={classNames(classes.bio, 'translate')}
|
||||||
htmlString={account.note_emojified}
|
htmlString={account.note_emojified}
|
||||||
|
|||||||
@ -8,13 +8,6 @@
|
|||||||
&[data-with-border='true'] {
|
&[data-with-border='true'] {
|
||||||
border-bottom: 1px solid var(--color-border-primary);
|
border-bottom: 1px solid var(--color-border-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.account__note) {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 3;
|
|
||||||
line-clamp: 3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
@ -40,6 +33,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bio {
|
.bio {
|
||||||
|
overflow: hidden;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
line-clamp: 3;
|
||||||
|
|
||||||
:any-link {
|
:any-link {
|
||||||
color: var(--color-text-status-links);
|
color: var(--color-text-status-links);
|
||||||
|
|
||||||
|
|||||||
@ -73,7 +73,7 @@ const BackButton: React.FC<{
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
title?: string;
|
title?: React.ReactNode;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
iconComponent?: IconProp;
|
iconComponent?: IconProp;
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
|
|||||||
@ -3,16 +3,20 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
padding: 20px;
|
padding: 24px;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: var(--color-text-primary);
|
color: var(--color-text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
max-width: 370px;
|
||||||
|
|
||||||
svg,
|
svg,
|
||||||
img {
|
img {
|
||||||
width: 240px;
|
width: 200px;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
object-fit: contain;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
@ -20,11 +24,14 @@
|
|||||||
h3 {
|
h3 {
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
text-wrap: balance;
|
||||||
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
font-size: 15px;
|
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
|
font-size: 15px;
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
|
text-wrap: pretty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
.menuButton {
|
.menuButton {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset-inline-end: 0;
|
inset-inline-end: 1px;
|
||||||
top: 0;
|
top: 1px;
|
||||||
padding: 9px;
|
padding: 7px;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
// Subtle divider line separating the button from the input field
|
// Subtle divider line separating the button from the input field
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
.copyButton {
|
.copyButton {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset-inline-end: 0;
|
inset-inline-end: 1px;
|
||||||
top: 0;
|
top: 1px;
|
||||||
padding: 9px;
|
padding: 7px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
@ -5,17 +7,21 @@ import { Link } from 'react-router-dom';
|
|||||||
|
|
||||||
import ElephantDarkImage from '@/images/elephant_ui_dark.svg?react';
|
import ElephantDarkImage from '@/images/elephant_ui_dark.svg?react';
|
||||||
import ElephantLightImage from '@/images/elephant_ui_light.svg?react';
|
import ElephantLightImage from '@/images/elephant_ui_light.svg?react';
|
||||||
|
import { openModal } from '@/mastodon/actions/modal';
|
||||||
|
import { Button } from '@/mastodon/components/button';
|
||||||
import { EmptyState } from '@/mastodon/components/empty_state';
|
import { EmptyState } from '@/mastodon/components/empty_state';
|
||||||
import { LimitedAccountHint } from '@/mastodon/features/account_timeline/components/limited_account_hint';
|
import { LimitedAccountHint } from '@/mastodon/features/account_timeline/components/limited_account_hint';
|
||||||
import { areCollectionsEnabled } from '@/mastodon/features/collections/utils';
|
import { areCollectionsEnabled } from '@/mastodon/features/collections/utils';
|
||||||
import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId';
|
import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId';
|
||||||
import { useTheme } from '@/mastodon/hooks/useTheme';
|
import { useTheme } from '@/mastodon/hooks/useTheme';
|
||||||
|
import { useAppDispatch } from '@/mastodon/store';
|
||||||
|
|
||||||
interface EmptyMessageProps {
|
interface EmptyMessageProps {
|
||||||
suspended: boolean;
|
suspended: boolean;
|
||||||
hidden: boolean;
|
hidden: boolean;
|
||||||
blockedBy: boolean;
|
blockedBy: boolean;
|
||||||
accountId?: string;
|
accountId?: string;
|
||||||
|
withoutAddCollectionButton?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
||||||
@ -23,6 +29,7 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
suspended,
|
suspended,
|
||||||
hidden,
|
hidden,
|
||||||
blockedBy,
|
blockedBy,
|
||||||
|
withoutAddCollectionButton,
|
||||||
}) => {
|
}) => {
|
||||||
const { acct } = useParams<{ acct?: string }>();
|
const { acct } = useParams<{ acct?: string }>();
|
||||||
const me = useCurrentAccountId();
|
const me = useCurrentAccountId();
|
||||||
@ -30,6 +37,17 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
const ElephantImage =
|
const ElephantImage =
|
||||||
theme === 'dark' ? ElephantDarkImage : ElephantLightImage;
|
theme === 'dark' ? ElephantDarkImage : ElephantLightImage;
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const confirmHideFeaturedTab = useCallback(() => {
|
||||||
|
void dispatch(
|
||||||
|
openModal({
|
||||||
|
modalType: 'ACCOUNT_HIDE_FEATURED_TAB',
|
||||||
|
modalProps: {},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
if (!accountId) {
|
if (!accountId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -49,17 +67,31 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
image={image}
|
image={image}
|
||||||
title={
|
title={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.account_featured_self.no_collections'
|
id='empty_column.account_featured_self.showcase_accounts'
|
||||||
defaultMessage='No collections yet'
|
defaultMessage='Showcase your favorite accounts'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
message={
|
||||||
|
<FormattedMessage
|
||||||
|
id='empty_column.account_featured_self.showcase_accounts_desc'
|
||||||
|
defaultMessage='Collections are curated lists of accounts to help others discover more of the Fediverse.'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{!withoutAddCollectionButton && (
|
||||||
<Link to='/collections/new' className='button'>
|
<Link to='/collections/new' className='button'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.account_featured_self.no_collections_button'
|
id='empty_column.account_featured_self.no_collections_button'
|
||||||
defaultMessage='Create a collection'
|
defaultMessage='Create a collection'
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
)}
|
||||||
|
<Button secondary onClick={confirmHideFeaturedTab}>
|
||||||
|
<FormattedMessage
|
||||||
|
id='empty_column.account_featured_self.no_collections_hide_tab'
|
||||||
|
defaultMessage='Hide this tab instead'
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -72,7 +104,7 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
message = (
|
message = (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.account_featured_self.pre_collections_desc'
|
id='empty_column.account_featured_self.pre_collections_desc'
|
||||||
defaultMessage='Collections (coming in Mastodon 4.6) allows you to create your own curated lists of accounts to recommend to others.'
|
defaultMessage='Collections (coming in Mastodon 4.6) allow you to create your own curated lists of accounts to recommend to others.'
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -93,49 +125,23 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Standard other account empty state.
|
if (acct) {
|
||||||
title = (
|
title = (
|
||||||
<FormattedMessage
|
|
||||||
id='empty_column.account_featured_other.title'
|
|
||||||
defaultMessage='Nothing to see here'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
if (hasCollections) {
|
|
||||||
if (acct) {
|
|
||||||
message = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='empty_column.account_featured_other.no_collections_desc'
|
|
||||||
defaultMessage='{acct} hasn’t created any collections yet.'
|
|
||||||
values={{ acct }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
message = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='empty_column.account_featured_unknown.no_collections_desc'
|
|
||||||
defaultMessage='This account hasn’t created any collections yet.'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (acct) {
|
|
||||||
message = (
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.account_featured.other'
|
id='empty_column.account_featured.other'
|
||||||
defaultMessage='{acct} hasn’t featured anything yet.'
|
defaultMessage='{acct} has not featured anything yet.'
|
||||||
values={{ acct }}
|
values={{ acct }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
message = (
|
title = (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.account_featured_unknown.other'
|
id='empty_column.account_featured_unknown.other'
|
||||||
defaultMessage='This account hasn’t featured anything yet.'
|
defaultMessage='This account has not featured anything yet.'
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return <EmptyState title={title} message={message} image={image} />;
|
return <EmptyState title={title} message={message} image={image} />;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
.subheading {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
min-height: 52px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
background: var(--color-bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
display: flex;
|
||||||
|
padding-block: 4px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: none;
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: var(--outline-focus-default);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.icon) {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
import type { ComponentPropsWithoutRef } from 'react';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import type { IconProp } from '@/mastodon/components/icon';
|
||||||
|
import { Icon } from '@/mastodon/components/icon';
|
||||||
|
import { polymorphicForwardRef } from '@/types/polymorphic';
|
||||||
|
|
||||||
|
import classes from './subheading.module.scss';
|
||||||
|
|
||||||
|
export const Subheading = polymorphicForwardRef<'h2'>(
|
||||||
|
({ as: Component = 'h2', children, className, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<Component
|
||||||
|
ref={ref}
|
||||||
|
className={classNames(classes.subheading, className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Component>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
interface SubheadingLinkProps extends ComponentPropsWithoutRef<typeof Link> {
|
||||||
|
icon: IconProp;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SubheadingLink: React.FC<SubheadingLinkProps> = ({
|
||||||
|
icon,
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Link className={classNames(classes.link, className)} {...props}>
|
||||||
|
<Icon id='subheading-icon' icon={icon} />
|
||||||
|
{children}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -6,9 +6,10 @@ import { useHistory } from 'react-router';
|
|||||||
|
|
||||||
import { List as ImmutableList } from 'immutable';
|
import { List as ImmutableList } from 'immutable';
|
||||||
|
|
||||||
|
import { AccountListItem } from '@/mastodon/components/account_list_item';
|
||||||
import { useAccount } from '@/mastodon/hooks/useAccount';
|
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||||
|
import AddIcon from '@/material-icons/400-24px/add.svg?react';
|
||||||
import { fetchEndorsedAccounts } from 'mastodon/actions/accounts';
|
import { fetchEndorsedAccounts } from 'mastodon/actions/accounts';
|
||||||
import { Account } from 'mastodon/components/account';
|
|
||||||
import { ColumnBackButton } from 'mastodon/components/column_back_button';
|
import { ColumnBackButton } from 'mastodon/components/column_back_button';
|
||||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import { RemoteHint } from 'mastodon/components/remote_hint';
|
import { RemoteHint } from 'mastodon/components/remote_hint';
|
||||||
@ -28,10 +29,13 @@ import {
|
|||||||
} from 'mastodon/reducers/slices/collections';
|
} from 'mastodon/reducers/slices/collections';
|
||||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||||
|
|
||||||
import { CollectionListItem } from '../collections/detail/collection_list_item';
|
import { CollectionListItem } from '../collections/components/collection_list_item';
|
||||||
import { areCollectionsEnabled } from '../collections/utils';
|
import { areCollectionsEnabled } from '../collections/utils';
|
||||||
|
|
||||||
import { EmptyMessage } from './components/empty_message';
|
import { EmptyMessage } from './components/empty_message';
|
||||||
|
import { Subheading, SubheadingLink } from './components/subheading';
|
||||||
|
|
||||||
|
const collectionsEnabled = areCollectionsEnabled();
|
||||||
|
|
||||||
const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
||||||
multiColumn,
|
multiColumn,
|
||||||
@ -54,13 +58,12 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
if (accountId) {
|
if (accountId) {
|
||||||
void dispatch(fetchEndorsedAccounts({ accountId }));
|
void dispatch(fetchEndorsedAccounts({ accountId }));
|
||||||
|
|
||||||
if (areCollectionsEnabled()) {
|
if (collectionsEnabled) {
|
||||||
void dispatch(fetchAccountCollections({ accountId }));
|
void dispatch(fetchAccountCollections({ accountId }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [accountId, dispatch]);
|
}, [accountId, dispatch]);
|
||||||
|
|
||||||
const isLoading = !accountId;
|
|
||||||
const featuredAccountIds = useAppSelector(
|
const featuredAccountIds = useAppSelector(
|
||||||
(state) =>
|
(state) =>
|
||||||
state.user_lists.getIn(
|
state.user_lists.getIn(
|
||||||
@ -68,8 +71,8 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
ImmutableList(),
|
ImmutableList(),
|
||||||
) as ImmutableList<string>,
|
) as ImmutableList<string>,
|
||||||
);
|
);
|
||||||
const { collections, status } = useAppSelector((state) =>
|
const { collections, status: collectionsLoadStatus } = useAppSelector(
|
||||||
selectAccountCollections(state, accountId ?? null),
|
(state) => selectAccountCollections(state, accountId ?? null),
|
||||||
);
|
);
|
||||||
const listedCollections = collections.filter(
|
const listedCollections = collections.filter(
|
||||||
// Hide unlisted and empty collections to avoid confusion
|
// Hide unlisted and empty collections to avoid confusion
|
||||||
@ -78,6 +81,15 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
(item) => item.discoverable && !!item.item_count,
|
(item) => item.discoverable && !!item.item_count,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hasCollections =
|
||||||
|
collectionsEnabled &&
|
||||||
|
collectionsLoadStatus === 'idle' &&
|
||||||
|
listedCollections.length > 0;
|
||||||
|
|
||||||
|
const hasFeaturedAccounts = !featuredAccountIds.isEmpty();
|
||||||
|
|
||||||
|
const isLoading = !accountId || collectionsLoadStatus !== 'idle';
|
||||||
|
|
||||||
if (accountId === null) {
|
if (accountId === null) {
|
||||||
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
|
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
|
||||||
}
|
}
|
||||||
@ -92,7 +104,7 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (featuredAccountIds.isEmpty() && listedCollections.length === 0) {
|
if (!hasFeaturedAccounts && !hasCollections) {
|
||||||
return (
|
return (
|
||||||
<AccountFeaturedWrapper accountId={accountId}>
|
<AccountFeaturedWrapper accountId={accountId}>
|
||||||
<EmptyMessage
|
<EmptyMessage
|
||||||
@ -114,14 +126,45 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
{accountId && (
|
{accountId && (
|
||||||
<AccountHeader accountId={accountId} hideTabs={forceEmptyState} />
|
<AccountHeader accountId={accountId} hideTabs={forceEmptyState} />
|
||||||
)}
|
)}
|
||||||
{listedCollections.length > 0 && status === 'idle' && (
|
{!featuredAccountIds.isEmpty() && (
|
||||||
<>
|
<>
|
||||||
<h4 className='column-subheading'>
|
<Subheading as='h2'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='account.featured.accounts'
|
||||||
|
defaultMessage='Profiles'
|
||||||
|
/>
|
||||||
|
</Subheading>
|
||||||
|
<ItemList>
|
||||||
|
{featuredAccountIds.map((featuredAccountId, index) => (
|
||||||
|
<Article
|
||||||
|
focusable
|
||||||
|
key={featuredAccountId}
|
||||||
|
aria-posinset={index + 1}
|
||||||
|
aria-setsize={featuredAccountIds.size}
|
||||||
|
>
|
||||||
|
<AccountListItem accountId={featuredAccountId} />
|
||||||
|
</Article>
|
||||||
|
))}
|
||||||
|
</ItemList>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{collectionsEnabled && (
|
||||||
|
<>
|
||||||
|
<Subheading as='header'>
|
||||||
|
<h2>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='account.featured.collections'
|
id='account.featured.collections'
|
||||||
defaultMessage='Collections'
|
defaultMessage='Collections'
|
||||||
/>
|
/>
|
||||||
</h4>
|
</h2>
|
||||||
|
<SubheadingLink to='/collections/new' icon={AddIcon}>
|
||||||
|
<FormattedMessage
|
||||||
|
id='account.featured.new_collection'
|
||||||
|
defaultMessage='New collection'
|
||||||
|
/>
|
||||||
|
</SubheadingLink>
|
||||||
|
</Subheading>
|
||||||
|
{hasCollections ? (
|
||||||
<ItemList>
|
<ItemList>
|
||||||
{listedCollections.map((item, index) => (
|
{listedCollections.map((item, index) => (
|
||||||
<CollectionListItem
|
<CollectionListItem
|
||||||
@ -134,28 +177,15 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ItemList>
|
</ItemList>
|
||||||
</>
|
) : (
|
||||||
)}
|
<EmptyMessage
|
||||||
{!featuredAccountIds.isEmpty() && (
|
withoutAddCollectionButton
|
||||||
<>
|
blockedBy={blockedBy}
|
||||||
<h4 className='column-subheading'>
|
hidden={hidden}
|
||||||
<FormattedMessage
|
suspended={suspended}
|
||||||
id='account.featured.accounts'
|
accountId={accountId}
|
||||||
defaultMessage='Profiles'
|
|
||||||
/>
|
/>
|
||||||
</h4>
|
)}
|
||||||
<ItemList>
|
|
||||||
{featuredAccountIds.map((featuredAccountId, index) => (
|
|
||||||
<Article
|
|
||||||
focusable
|
|
||||||
key={featuredAccountId}
|
|
||||||
aria-posinset={index + 1}
|
|
||||||
aria-setsize={featuredAccountIds.size}
|
|
||||||
>
|
|
||||||
<Account id={featuredAccountId} />
|
|
||||||
</Article>
|
|
||||||
))}
|
|
||||||
</ItemList>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<RemoteHint accountId={accountId} />
|
<RemoteHint accountId={accountId} />
|
||||||
|
|||||||
@ -8,8 +8,6 @@ import { NavLink } from 'react-router-dom';
|
|||||||
import { useAccount } from '@/mastodon/hooks/useAccount';
|
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||||
import { useAccountId } from '@/mastodon/hooks/useAccountId';
|
import { useAccountId } from '@/mastodon/hooks/useAccountId';
|
||||||
|
|
||||||
import { areCollectionsEnabled } from '../../collections/utils';
|
|
||||||
|
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
const isActive: Required<NavLinkProps>['isActive'] = (match, location) =>
|
const isActive: Required<NavLinkProps>['isActive'] = (match, location) =>
|
||||||
@ -41,14 +39,7 @@ export const AccountTabs: FC = () => {
|
|||||||
)}
|
)}
|
||||||
{show_featured && (
|
{show_featured && (
|
||||||
<NavLink exact to={`/@${acct}/featured`}>
|
<NavLink exact to={`/@${acct}/featured`}>
|
||||||
{areCollectionsEnabled() ? (
|
|
||||||
<FormattedMessage
|
|
||||||
id='account.featured.collections'
|
|
||||||
defaultMessage='Collections'
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<FormattedMessage id='account.featured' defaultMessage='Featured' />
|
<FormattedMessage id='account.featured' defaultMessage='Featured' />
|
||||||
)}
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
padding: 12px 16px;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
&:not(.wrapperWithoutBorder) {
|
||||||
|
border-bottom: 1px solid var(--color-border-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuButton {
|
||||||
|
padding: 4px;
|
||||||
|
margin-top: -2px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
import { useId } from 'react';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { Article } from 'mastodon/components/scrollable_list/components';
|
||||||
|
import type { CollectionLockupProps } from 'mastodon/features/collections/components/collection_lockup';
|
||||||
|
import { CollectionLockup } from 'mastodon/features/collections/components/collection_lockup';
|
||||||
|
import { CollectionMenu } from 'mastodon/features/collections/components/collection_menu';
|
||||||
|
|
||||||
|
import classes from './collection_list_item.module.scss';
|
||||||
|
|
||||||
|
interface CollectionListItemProps extends CollectionLockupProps {
|
||||||
|
withoutBorder?: boolean;
|
||||||
|
positionInList: number;
|
||||||
|
listSize: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CollectionListItem: React.FC<CollectionListItemProps> = ({
|
||||||
|
collection,
|
||||||
|
withoutBorder,
|
||||||
|
positionInList,
|
||||||
|
listSize,
|
||||||
|
...otherProps
|
||||||
|
}) => {
|
||||||
|
const uniqueId = useId();
|
||||||
|
const linkId = `${uniqueId}-link`;
|
||||||
|
const infoId = `${uniqueId}-info`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Article
|
||||||
|
focusable
|
||||||
|
className={classNames(
|
||||||
|
classes.wrapper,
|
||||||
|
withoutBorder && classes.wrapperWithoutBorder,
|
||||||
|
)}
|
||||||
|
aria-labelledby={linkId}
|
||||||
|
aria-describedby={infoId}
|
||||||
|
aria-posinset={positionInList}
|
||||||
|
aria-setsize={listSize}
|
||||||
|
>
|
||||||
|
<CollectionLockup collection={collection} {...otherProps} />
|
||||||
|
|
||||||
|
<CollectionMenu
|
||||||
|
context='list'
|
||||||
|
collection={collection}
|
||||||
|
className={classes.menuButton}
|
||||||
|
/>
|
||||||
|
</Article>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,21 +1,11 @@
|
|||||||
.wrapper {
|
|
||||||
display: flex;
|
|
||||||
align-items: start;
|
|
||||||
margin-inline: 24px;
|
|
||||||
padding-block: 12px;
|
|
||||||
gap: 16px;
|
|
||||||
|
|
||||||
&:not(.wrapperWithoutBorder) {
|
|
||||||
border-bottom: 1px solid var(--color-border-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
column-gap: 12px;
|
column-gap: 12px;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatarGrid {
|
.avatarGrid {
|
||||||
@ -70,13 +60,3 @@
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuButton {
|
|
||||||
padding: 4px;
|
|
||||||
margin-top: -2px;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
import { useId } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import WarningIcon from '@/material-icons/400-24px/warning.svg?react';
|
||||||
|
import type { ApiCollectionJSON } from 'mastodon/api_types/collections';
|
||||||
|
import { AvatarById } from 'mastodon/components/avatar';
|
||||||
|
import { useAccountHandle } from 'mastodon/components/display_name/default';
|
||||||
|
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
||||||
|
import { useAccount } from 'mastodon/hooks/useAccount';
|
||||||
|
import { domain } from 'mastodon/initial_state';
|
||||||
|
|
||||||
|
import classes from './collection_lockup.module.scss';
|
||||||
|
|
||||||
|
export const AvatarGrid: React.FC<{
|
||||||
|
accountIds: (string | undefined)[];
|
||||||
|
sensitive?: boolean;
|
||||||
|
}> = ({ accountIds: ids, sensitive }) => {
|
||||||
|
const avatarIds = [ids[0], ids[1], ids[2], ids[3]];
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
classes.avatarGrid,
|
||||||
|
sensitive ? classes.avatarGridSensitive : null,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{avatarIds.map((id) => (
|
||||||
|
<AvatarById
|
||||||
|
animate={false}
|
||||||
|
key={id}
|
||||||
|
accountId={id}
|
||||||
|
className={classes.avatar}
|
||||||
|
size={25}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{sensitive && <WarningIcon className={classes.avatarSensitiveBadge} />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface CollectionLockupProps {
|
||||||
|
collection: ApiCollectionJSON;
|
||||||
|
withAuthorHandle?: boolean;
|
||||||
|
withTimestamp?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CollectionLockup: React.FC<CollectionLockupProps> = ({
|
||||||
|
collection,
|
||||||
|
withAuthorHandle = true,
|
||||||
|
withTimestamp,
|
||||||
|
}) => {
|
||||||
|
const { id, name } = collection;
|
||||||
|
const uniqueId = useId();
|
||||||
|
const linkId = `${uniqueId}-link`;
|
||||||
|
const infoId = `${uniqueId}-info`;
|
||||||
|
const authorAccount = useAccount(collection.account_id);
|
||||||
|
const authorHandle = useAccountHandle(authorAccount, domain);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.content}>
|
||||||
|
<AvatarGrid
|
||||||
|
accountIds={collection.items.map((item) => item.account_id)}
|
||||||
|
sensitive={collection.sensitive}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<h2 id={linkId}>
|
||||||
|
<Link to={`/collections/${id}`} className={classes.link}>
|
||||||
|
{name}
|
||||||
|
</Link>
|
||||||
|
</h2>
|
||||||
|
<ul className={classes.info} id={infoId}>
|
||||||
|
{collection.sensitive && (
|
||||||
|
<li className='sr-only'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='collections.sensitive'
|
||||||
|
defaultMessage='Sensitive'
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
{withAuthorHandle && authorAccount && (
|
||||||
|
<FormattedMessage
|
||||||
|
id='collections.by_account'
|
||||||
|
defaultMessage='by {account_handle}'
|
||||||
|
values={{
|
||||||
|
account_handle: authorHandle,
|
||||||
|
}}
|
||||||
|
tagName='li'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<FormattedMessage
|
||||||
|
id='collections.account_count'
|
||||||
|
defaultMessage='{count, plural, one {# account} other {# accounts}}'
|
||||||
|
values={{ count: collection.item_count }}
|
||||||
|
tagName='li'
|
||||||
|
/>
|
||||||
|
{withTimestamp && (
|
||||||
|
<FormattedMessage
|
||||||
|
id='collections.last_updated_at'
|
||||||
|
defaultMessage='Last updated: {date}'
|
||||||
|
values={{
|
||||||
|
date: (
|
||||||
|
<RelativeTimestamp timestamp={collection.updated_at} long />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
tagName='li'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
padding: 12px;
|
||||||
|
gap: 12px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid var(--color-border-primary);
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
import type { CollectionLockupProps } from 'mastodon/features/collections/components/collection_lockup';
|
||||||
|
import { CollectionLockup } from 'mastodon/features/collections/components/collection_lockup';
|
||||||
|
|
||||||
|
import classes from './collection_preview_card.module.scss';
|
||||||
|
|
||||||
|
interface CollectionPreviewCardProps extends CollectionLockupProps {
|
||||||
|
onRemove?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CollectionPreviewCard: React.FC<CollectionPreviewCardProps> = ({
|
||||||
|
collection,
|
||||||
|
onRemove,
|
||||||
|
...otherProps
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className={classes.wrapper}>
|
||||||
|
<CollectionLockup collection={collection} {...otherProps} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -5,27 +5,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.preview {
|
.preview {
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap-reverse;
|
|
||||||
align-items: start;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 16px;
|
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
border-radius: 8px;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: linear-gradient(
|
|
||||||
145deg,
|
|
||||||
var(--color-bg-brand-soft),
|
|
||||||
var(--color-bg-primary)
|
|
||||||
);
|
|
||||||
border: 1px solid var(--color-bg-brand-base);
|
|
||||||
}
|
|
||||||
|
|
||||||
.previewHeading {
|
|
||||||
font-size: 22px;
|
|
||||||
line-height: 1.3;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
@ -8,8 +8,6 @@ import { me } from '@/mastodon/initial_state';
|
|||||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||||
import { changeCompose, focusCompose } from 'mastodon/actions/compose';
|
import { changeCompose, focusCompose } from 'mastodon/actions/compose';
|
||||||
import type { ApiCollectionJSON } from 'mastodon/api_types/collections';
|
import type { ApiCollectionJSON } from 'mastodon/api_types/collections';
|
||||||
import { AvatarById } from 'mastodon/components/avatar';
|
|
||||||
import { AvatarGroup } from 'mastodon/components/avatar_group';
|
|
||||||
import { Button } from 'mastodon/components/button';
|
import { Button } from 'mastodon/components/button';
|
||||||
import { CopyLinkField } from 'mastodon/components/form_fields';
|
import { CopyLinkField } from 'mastodon/components/form_fields';
|
||||||
import { IconButton } from 'mastodon/components/icon_button';
|
import { IconButton } from 'mastodon/components/icon_button';
|
||||||
@ -20,7 +18,7 @@ import {
|
|||||||
} from 'mastodon/components/modal_shell';
|
} from 'mastodon/components/modal_shell';
|
||||||
import { useAppDispatch } from 'mastodon/store';
|
import { useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
import { AuthorNote } from '.';
|
import { CollectionPreviewCard } from './collection_preview_card';
|
||||||
import classes from './share_modal.module.scss';
|
import classes from './share_modal.module.scss';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
@ -95,24 +93,13 @@ export const CollectionShareModal: React.FC<{
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={classes.preview}>
|
<div className={classes.preview}>
|
||||||
<div>
|
<CollectionPreviewCard collection={collection} />
|
||||||
<h2 className={classes.previewHeading}>{collection.name}</h2>
|
|
||||||
<AuthorNote id={collection.account_id} />
|
|
||||||
</div>
|
|
||||||
<AvatarGroup>
|
|
||||||
{collection.items.slice(0, 5).map(({ account_id }) => {
|
|
||||||
if (!account_id) return;
|
|
||||||
return (
|
|
||||||
<AvatarById key={account_id} accountId={account_id} size={28} />
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</AvatarGroup>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CopyLinkField
|
<CopyLinkField
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
id: 'collection.share_modal.share_link_label',
|
id: 'collection.share_modal.share_link_label',
|
||||||
defaultMessage: 'Invite share link',
|
defaultMessage: 'Share link',
|
||||||
})}
|
})}
|
||||||
value={collectionLink}
|
value={collectionLink}
|
||||||
/>
|
/>
|
||||||
@ -146,7 +146,6 @@ export const CollectionAccountsList: React.FC<{
|
|||||||
<AccountListItem
|
<AccountListItem
|
||||||
accountId={account_id}
|
accountId={account_id}
|
||||||
withBorder={index !== items.length - 1}
|
withBorder={index !== items.length - 1}
|
||||||
stats={['followers', 'last-active']}
|
|
||||||
renderButton={renderAccountItemButton}
|
renderButton={renderAccountItemButton}
|
||||||
/>
|
/>
|
||||||
</Article>
|
</Article>
|
||||||
|
|||||||
@ -1,139 +0,0 @@
|
|||||||
import { useId } from 'react';
|
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
|
|
||||||
import WarningIcon from '@/material-icons/400-24px/warning.svg?react';
|
|
||||||
import type { ApiCollectionJSON } from 'mastodon/api_types/collections';
|
|
||||||
import { AvatarById } from 'mastodon/components/avatar';
|
|
||||||
import { useAccountHandle } from 'mastodon/components/display_name/default';
|
|
||||||
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
|
||||||
import { Article } from 'mastodon/components/scrollable_list/components';
|
|
||||||
import { useAccount } from 'mastodon/hooks/useAccount';
|
|
||||||
import { domain } from 'mastodon/initial_state';
|
|
||||||
|
|
||||||
import classes from './collection_list_item.module.scss';
|
|
||||||
import { CollectionMenu } from './collection_menu';
|
|
||||||
|
|
||||||
export const AvatarGrid: React.FC<{
|
|
||||||
accountIds: (string | undefined)[];
|
|
||||||
sensitive?: boolean;
|
|
||||||
}> = ({ accountIds: ids, sensitive }) => {
|
|
||||||
const avatarIds = [ids[0], ids[1], ids[2], ids[3]];
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
classes.avatarGrid,
|
|
||||||
sensitive ? classes.avatarGridSensitive : null,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{avatarIds.map((id) => (
|
|
||||||
<AvatarById
|
|
||||||
animate={false}
|
|
||||||
key={id}
|
|
||||||
accountId={id}
|
|
||||||
className={classes.avatar}
|
|
||||||
size={25}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
{sensitive && <WarningIcon className={classes.avatarSensitiveBadge} />}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CollectionListItem: React.FC<{
|
|
||||||
collection: ApiCollectionJSON;
|
|
||||||
withoutBorder?: boolean;
|
|
||||||
withAuthorHandle?: boolean;
|
|
||||||
withTimestamp?: boolean;
|
|
||||||
positionInList: number;
|
|
||||||
listSize: number;
|
|
||||||
}> = ({
|
|
||||||
collection,
|
|
||||||
withoutBorder,
|
|
||||||
withAuthorHandle = true,
|
|
||||||
withTimestamp,
|
|
||||||
positionInList,
|
|
||||||
listSize,
|
|
||||||
}) => {
|
|
||||||
const { id, name } = collection;
|
|
||||||
const uniqueId = useId();
|
|
||||||
const linkId = `${uniqueId}-link`;
|
|
||||||
const infoId = `${uniqueId}-info`;
|
|
||||||
const authorAccount = useAccount(collection.account_id);
|
|
||||||
const authorHandle = useAccountHandle(authorAccount, domain);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Article
|
|
||||||
focusable
|
|
||||||
className={classNames(
|
|
||||||
classes.wrapper,
|
|
||||||
withoutBorder && classes.wrapperWithoutBorder,
|
|
||||||
)}
|
|
||||||
aria-labelledby={linkId}
|
|
||||||
aria-describedby={infoId}
|
|
||||||
aria-posinset={positionInList}
|
|
||||||
aria-setsize={listSize}
|
|
||||||
>
|
|
||||||
<div className={classes.content}>
|
|
||||||
<AvatarGrid
|
|
||||||
accountIds={collection.items.map((item) => item.account_id)}
|
|
||||||
sensitive={collection.sensitive}
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<h2 id={linkId}>
|
|
||||||
<Link to={`/collections/${id}`} className={classes.link}>
|
|
||||||
{name}
|
|
||||||
</Link>
|
|
||||||
</h2>
|
|
||||||
<ul className={classes.info} id={infoId}>
|
|
||||||
{collection.sensitive && (
|
|
||||||
<li className='sr-only'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='collections.sensitive'
|
|
||||||
defaultMessage='Sensitive'
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
)}
|
|
||||||
{withAuthorHandle && authorAccount && (
|
|
||||||
<FormattedMessage
|
|
||||||
id='collections.by_account'
|
|
||||||
defaultMessage='by {account_handle}'
|
|
||||||
values={{
|
|
||||||
account_handle: authorHandle,
|
|
||||||
}}
|
|
||||||
tagName='li'
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<FormattedMessage
|
|
||||||
id='collections.account_count'
|
|
||||||
defaultMessage='{count, plural, one {# account} other {# accounts}}'
|
|
||||||
values={{ count: collection.item_count }}
|
|
||||||
tagName='li'
|
|
||||||
/>
|
|
||||||
{withTimestamp && (
|
|
||||||
<FormattedMessage
|
|
||||||
id='collections.last_updated_at'
|
|
||||||
defaultMessage='Last updated: {date}'
|
|
||||||
values={{
|
|
||||||
date: (
|
|
||||||
<RelativeTimestamp timestamp={collection.updated_at} long />
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
tagName='li'
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<CollectionMenu
|
|
||||||
context='list'
|
|
||||||
collection={collection}
|
|
||||||
className={classes.menuButton}
|
|
||||||
/>
|
|
||||||
</Article>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -23,8 +23,9 @@ import { domain, me } from 'mastodon/initial_state';
|
|||||||
import { fetchCollection } from 'mastodon/reducers/slices/collections';
|
import { fetchCollection } from 'mastodon/reducers/slices/collections';
|
||||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||||
|
|
||||||
|
import { CollectionMenu } from '../components/collection_menu';
|
||||||
|
|
||||||
import { CollectionAccountsList } from './accounts_list';
|
import { CollectionAccountsList } from './accounts_list';
|
||||||
import { CollectionMenu } from './collection_menu';
|
|
||||||
import { useConfirmRevoke } from './revoke_collection_inclusion_modal';
|
import { useConfirmRevoke } from './revoke_collection_inclusion_modal';
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ export const AuthorNote: React.FC<{ id: string }> = ({ id }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RevokeControls: React.FC<{
|
const RevokeControls: React.FC<{
|
||||||
collection: ApiCollectionJSON;
|
collection: ApiCollectionJSON;
|
||||||
}> = ({ collection }) => {
|
}> = ({ collection }) => {
|
||||||
const authorAccount = useAccount(collection.account_id);
|
const authorAccount = useAccount(collection.account_id);
|
||||||
|
|||||||
@ -61,9 +61,11 @@ const AddedAccountItem: React.FC<{
|
|||||||
onRemove(accountId);
|
onRemove(accountId);
|
||||||
}, [accountId, onRemove]);
|
}, [accountId, onRemove]);
|
||||||
|
|
||||||
|
const lastStatusAt = account?.last_status_at;
|
||||||
|
|
||||||
const lastPostHint = useMemo(
|
const lastPostHint = useMemo(
|
||||||
() =>
|
() =>
|
||||||
isOlderThanAWeek(account?.last_status_at) && (
|
(!lastStatusAt || isOlderThanAWeek(lastStatusAt)) && (
|
||||||
<Badge
|
<Badge
|
||||||
label={
|
label={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
@ -75,7 +77,7 @@ const AddedAccountItem: React.FC<{
|
|||||||
className={classes.accountBadge}
|
className={classes.accountBadge}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[account?.last_status_at],
|
[lastStatusAt],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -10,22 +10,29 @@ import CollectionsFilledIcon from '@/material-icons/400-24px/category-fill.svg?r
|
|||||||
import SquigglyArrow from '@/svg-icons/squiggly_arrow.svg?react';
|
import SquigglyArrow from '@/svg-icons/squiggly_arrow.svg?react';
|
||||||
import { Column } from 'mastodon/components/column';
|
import { Column } from 'mastodon/components/column';
|
||||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||||
|
import { DisplayNameSimple } from 'mastodon/components/display_name/simple';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import {
|
import {
|
||||||
ItemList,
|
ItemList,
|
||||||
Scrollable,
|
Scrollable,
|
||||||
} from 'mastodon/components/scrollable_list/components';
|
} from 'mastodon/components/scrollable_list/components';
|
||||||
|
import { useAccount } from 'mastodon/hooks/useAccount';
|
||||||
|
import { useAccountId, useCurrentAccountId } from 'mastodon/hooks/useAccountId';
|
||||||
import {
|
import {
|
||||||
fetchAccountCollections,
|
fetchAccountCollections,
|
||||||
selectAccountCollections,
|
selectAccountCollections,
|
||||||
} from 'mastodon/reducers/slices/collections';
|
} from 'mastodon/reducers/slices/collections';
|
||||||
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
import { CollectionListItem } from './detail/collection_list_item';
|
import { CollectionListItem } from './components/collection_list_item';
|
||||||
import { messages as editorMessages } from './editor';
|
import { messages as editorMessages } from './editor';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
heading: { id: 'column.collections', defaultMessage: 'My collections' },
|
headingMe: { id: 'column.my_collections', defaultMessage: 'My collections' },
|
||||||
|
headingOther: {
|
||||||
|
id: 'column.other_collections',
|
||||||
|
defaultMessage: 'Collections by {name}',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const Collections: React.FC<{
|
export const Collections: React.FC<{
|
||||||
@ -33,17 +40,22 @@ export const Collections: React.FC<{
|
|||||||
}> = ({ multiColumn }) => {
|
}> = ({ multiColumn }) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const me = useAppSelector((state) => state.meta.get('me') as string);
|
const me = useCurrentAccountId();
|
||||||
|
const accountId = useAccountId();
|
||||||
|
const account = useAccount(accountId);
|
||||||
|
|
||||||
const { collections, status } = useAppSelector((state) =>
|
const { collections, status } = useAppSelector((state) =>
|
||||||
selectAccountCollections(state, me),
|
selectAccountCollections(state, accountId),
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void dispatch(fetchAccountCollections({ accountId: me }));
|
if (accountId) {
|
||||||
}, [dispatch, me]);
|
void dispatch(fetchAccountCollections({ accountId }));
|
||||||
|
}
|
||||||
|
}, [dispatch, accountId]);
|
||||||
|
|
||||||
const emptyMessage =
|
const emptyMessage =
|
||||||
status === 'error' ? (
|
status === 'error' || !accountId ? (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='collections.error_loading_collections'
|
id='collections.error_loading_collections'
|
||||||
defaultMessage='There was an error when trying to load your collections.'
|
defaultMessage='There was an error when trying to load your collections.'
|
||||||
@ -67,17 +79,27 @@ export const Collections: React.FC<{
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isOwnCollection = accountId === me;
|
||||||
|
const titleMessage = isOwnCollection
|
||||||
|
? messages.headingMe
|
||||||
|
: messages.headingOther;
|
||||||
|
|
||||||
|
const pageTitle = intl.formatMessage(titleMessage, {
|
||||||
|
name: account?.get('display_name'),
|
||||||
|
});
|
||||||
|
const pageTitleHtml = intl.formatMessage(titleMessage, {
|
||||||
|
name: <DisplayNameSimple account={account} />,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column
|
<Column bindToDocument={!multiColumn} label={pageTitle}>
|
||||||
bindToDocument={!multiColumn}
|
|
||||||
label={intl.formatMessage(messages.heading)}
|
|
||||||
>
|
|
||||||
<ColumnHeader
|
<ColumnHeader
|
||||||
title={intl.formatMessage(messages.heading)}
|
title={pageTitleHtml}
|
||||||
icon='collections'
|
icon='collections'
|
||||||
iconComponent={CollectionsFilledIcon}
|
iconComponent={CollectionsFilledIcon}
|
||||||
multiColumn={multiColumn}
|
multiColumn={multiColumn}
|
||||||
extraButton={
|
extraButton={
|
||||||
|
isOwnCollection && (
|
||||||
<Link
|
<Link
|
||||||
to='/collections/new'
|
to='/collections/new'
|
||||||
className='column-header__button'
|
className='column-header__button'
|
||||||
@ -86,6 +108,7 @@ export const Collections: React.FC<{
|
|||||||
>
|
>
|
||||||
<Icon id='plus' icon={AddIcon} />
|
<Icon id='plus' icon={AddIcon} />
|
||||||
</Link>
|
</Link>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -105,7 +128,7 @@ export const Collections: React.FC<{
|
|||||||
</Scrollable>
|
</Scrollable>
|
||||||
|
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{intl.formatMessage(messages.heading)}</title>
|
<title>{pageTitle}</title>
|
||||||
<meta name='robots' content='noindex' />
|
<meta name='robots' content='noindex' />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
</Column>
|
</Column>
|
||||||
|
|||||||
@ -53,12 +53,20 @@ export const AccountList: FC<AccountListProps> = ({
|
|||||||
}
|
}
|
||||||
const children =
|
const children =
|
||||||
list?.items.map((followerId) => (
|
list?.items.map((followerId) => (
|
||||||
<AccountListItem key={followerId} accountId={followerId} />
|
<AccountListItem
|
||||||
|
key={followerId}
|
||||||
|
accountId={followerId}
|
||||||
|
withBio={false}
|
||||||
|
/>
|
||||||
)) ?? [];
|
)) ?? [];
|
||||||
|
|
||||||
if (prependAccountId) {
|
if (prependAccountId) {
|
||||||
children.unshift(
|
children.unshift(
|
||||||
<AccountListItem key={prependAccountId} accountId={prependAccountId} />,
|
<AccountListItem
|
||||||
|
key={prependAccountId}
|
||||||
|
accountId={prependAccountId}
|
||||||
|
withBio={false}
|
||||||
|
/>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return children;
|
return children;
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import type { Map as ImmutableMap } from 'immutable';
|
|||||||
import { animated, useSpring } from '@react-spring/web';
|
import { animated, useSpring } from '@react-spring/web';
|
||||||
import { useDrag } from '@use-gesture/react';
|
import { useDrag } from '@use-gesture/react';
|
||||||
|
|
||||||
|
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||||
import AddIcon from '@/material-icons/400-24px/add.svg?react';
|
import AddIcon from '@/material-icons/400-24px/add.svg?react';
|
||||||
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
||||||
import BookmarksActiveIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react';
|
import BookmarksActiveIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react';
|
||||||
@ -212,6 +213,7 @@ export const NavigationPanel: React.FC<{ multiColumn?: boolean }> = ({
|
|||||||
const { signedIn, permissions, disabledAccountId } = useIdentity();
|
const { signedIn, permissions, disabledAccountId } = useIdentity();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const showSearch = useBreakpoint('full') && !multiColumn;
|
const showSearch = useBreakpoint('full') && !multiColumn;
|
||||||
|
const account = useAccount(me);
|
||||||
|
|
||||||
let banner: React.ReactNode;
|
let banner: React.ReactNode;
|
||||||
|
|
||||||
@ -335,7 +337,7 @@ export const NavigationPanel: React.FC<{ multiColumn?: boolean }> = ({
|
|||||||
{areCollectionsEnabled() && (
|
{areCollectionsEnabled() && (
|
||||||
<ColumnLink
|
<ColumnLink
|
||||||
transparent
|
transparent
|
||||||
to='/collections'
|
to={`/@${account?.acct}/collections`}
|
||||||
icon='collections'
|
icon='collections'
|
||||||
iconComponent={CollectionsIcon}
|
iconComponent={CollectionsIcon}
|
||||||
activeIconComponent={CollectionsActiveIcon}
|
activeIconComponent={CollectionsActiveIcon}
|
||||||
|
|||||||
@ -0,0 +1,69 @@
|
|||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { DisplayNameSimple } from '@/mastodon/components/display_name/simple';
|
||||||
|
import { Icon } from '@/mastodon/components/icon';
|
||||||
|
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||||
|
import CollectionsFilledIcon from '@/material-icons/400-24px/category-fill.svg?react';
|
||||||
|
import type {
|
||||||
|
NotificationGroupAddedToCollection,
|
||||||
|
NotificationGroupCollectionUpdate,
|
||||||
|
} from 'mastodon/models/notification_group';
|
||||||
|
|
||||||
|
import { CollectionPreviewCard } from '../../collections/components/collection_preview_card';
|
||||||
|
|
||||||
|
export const NotificationCollection: React.FC<{
|
||||||
|
notification:
|
||||||
|
| NotificationGroupAddedToCollection
|
||||||
|
| NotificationGroupCollectionUpdate;
|
||||||
|
unread: boolean;
|
||||||
|
}> = ({ notification, unread }) => {
|
||||||
|
const { collection, type } = notification;
|
||||||
|
const collectionCreatorAccount = useAccount(collection.account_id);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'notification-group',
|
||||||
|
`notification-group--${type}`,
|
||||||
|
{ 'notification-group--unread': unread },
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className='notification-group__icon'>
|
||||||
|
<Icon id='collection' icon={CollectionsFilledIcon} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='notification-group__main'>
|
||||||
|
<div className='notification-group__main__header'>
|
||||||
|
<div className='notification-group__main__header__label'>
|
||||||
|
{type === 'added_to_collection' && (
|
||||||
|
<FormattedMessage
|
||||||
|
id='notification.added_to_collection'
|
||||||
|
defaultMessage='{name} added you to a collection'
|
||||||
|
values={{
|
||||||
|
name: (
|
||||||
|
<DisplayNameSimple account={collectionCreatorAccount} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{type === 'collection_update' && (
|
||||||
|
<FormattedMessage
|
||||||
|
id='notification.collection_update'
|
||||||
|
defaultMessage='{name} edited a collection you’re in'
|
||||||
|
values={{
|
||||||
|
name: (
|
||||||
|
<DisplayNameSimple account={collectionCreatorAccount} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CollectionPreviewCard collection={collection} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -9,6 +9,7 @@ import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
|||||||
import { NotificationAdminReport } from './notification_admin_report';
|
import { NotificationAdminReport } from './notification_admin_report';
|
||||||
import { NotificationAdminSignUp } from './notification_admin_sign_up';
|
import { NotificationAdminSignUp } from './notification_admin_sign_up';
|
||||||
import { NotificationAnnualReport } from './notification_annual_report';
|
import { NotificationAnnualReport } from './notification_annual_report';
|
||||||
|
import { NotificationCollection } from './notification_collection';
|
||||||
import { NotificationFavourite } from './notification_favourite';
|
import { NotificationFavourite } from './notification_favourite';
|
||||||
import { NotificationFollow } from './notification_follow';
|
import { NotificationFollow } from './notification_follow';
|
||||||
import { NotificationFollowRequest } from './notification_follow_request';
|
import { NotificationFollowRequest } from './notification_follow_request';
|
||||||
@ -156,6 +157,15 @@ export const NotificationGroup: React.FC<{
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 'added_to_collection':
|
||||||
|
case 'collection_update':
|
||||||
|
content = (
|
||||||
|
<NotificationCollection
|
||||||
|
unread={unread}
|
||||||
|
notification={notificationGroup}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
const ColumnSubheading = ({ text }) => {
|
|
||||||
return (
|
|
||||||
<div className='column-subheading'>
|
|
||||||
{text}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
ColumnSubheading.propTypes = {
|
|
||||||
text: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ColumnSubheading;
|
|
||||||
@ -4,6 +4,8 @@ import { defineMessages, useIntl } from 'react-intl';
|
|||||||
|
|
||||||
import { useHistory } from 'react-router';
|
import { useHistory } from 'react-router';
|
||||||
|
|
||||||
|
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||||
|
import { me } from '@/mastodon/initial_state';
|
||||||
import { deleteCollection } from 'mastodon/reducers/slices/collections';
|
import { deleteCollection } from 'mastodon/reducers/slices/collections';
|
||||||
import { useAppDispatch } from 'mastodon/store';
|
import { useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
@ -34,11 +36,12 @@ export const ConfirmDeleteCollectionModal: React.FC<
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const { acct: currentUserName } = useAccount(me) ?? {};
|
||||||
|
|
||||||
const onConfirm = useCallback(() => {
|
const onConfirm = useCallback(() => {
|
||||||
void dispatch(deleteCollection({ collectionId: id }));
|
void dispatch(deleteCollection({ collectionId: id }));
|
||||||
history.push('/collections');
|
history.push(`/@${currentUserName}/collections`);
|
||||||
}, [dispatch, history, id]);
|
}, [dispatch, history, id, currentUserName]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
|
|||||||
@ -0,0 +1,73 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import { useHistory } from 'react-router';
|
||||||
|
|
||||||
|
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||||
|
import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId';
|
||||||
|
import { domain } from '@/mastodon/initial_state';
|
||||||
|
import { patchProfile } from '@/mastodon/reducers/slices/profile_edit';
|
||||||
|
import { useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
|
import type { BaseConfirmationModalProps } from './confirmation_modal';
|
||||||
|
import { ConfirmationModal } from './confirmation_modal';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
title: {
|
||||||
|
id: 'confirmations.hide_featured_tab.title',
|
||||||
|
defaultMessage: 'Hide "Featured" tab?',
|
||||||
|
},
|
||||||
|
intro: {
|
||||||
|
id: 'confirmations.hide_featured_tab.intro',
|
||||||
|
defaultMessage:
|
||||||
|
'You can change this at any time under <i>Edit profile > Profile tab settings</i>.',
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
id: 'confirmations.hide_featured_tab.message',
|
||||||
|
defaultMessage:
|
||||||
|
'This will hide the tab for users on {serverName} and other servers running the latest version of Mastodon. Other displays may vary.',
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
id: 'confirmations.hide_featured_tab.confirm',
|
||||||
|
defaultMessage: 'Hide tab',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ConfirmHideFeaturedTabModal: React.FC<
|
||||||
|
BaseConfirmationModalProps
|
||||||
|
> = ({ onClose }) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const history = useHistory();
|
||||||
|
const currentAccountId = useCurrentAccountId();
|
||||||
|
const { acct: currentUserName } = useAccount(currentAccountId) ?? {};
|
||||||
|
|
||||||
|
const onConfirm = useCallback(() => {
|
||||||
|
void dispatch(patchProfile({ show_featured: false }));
|
||||||
|
history.push(`/@${currentUserName}`);
|
||||||
|
}, [currentUserName, dispatch, history]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmationModal
|
||||||
|
title={intl.formatMessage(messages.title)}
|
||||||
|
extraContent={
|
||||||
|
<div className='prose'>
|
||||||
|
<p>
|
||||||
|
{intl.formatMessage(messages.intro, {
|
||||||
|
i: (words) => <i>{words}</i>,
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{intl.formatMessage(messages.message, {
|
||||||
|
serverName: domain,
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
confirm={intl.formatMessage(messages.confirm)}
|
||||||
|
onConfirm={onConfirm}
|
||||||
|
onClose={onClose}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -79,7 +79,7 @@ export const MODAL_COMPONENTS = {
|
|||||||
'DOMAIN_BLOCK': DomainBlockModal,
|
'DOMAIN_BLOCK': DomainBlockModal,
|
||||||
'REPORT': ReportModal,
|
'REPORT': ReportModal,
|
||||||
'REPORT_COLLECTION': ReportCollectionModal,
|
'REPORT_COLLECTION': ReportCollectionModal,
|
||||||
'SHARE_COLLECTION': () => import('@/mastodon/features/collections/detail/share_modal').then(module => ({ default: module.CollectionShareModal })),
|
'SHARE_COLLECTION': () => import('@/mastodon/features/collections/components/share_modal').then(module => ({ default: module.CollectionShareModal })),
|
||||||
'REVOKE_COLLECTION_INCLUSION': () => import('@/mastodon/features/collections/detail/revoke_collection_inclusion_modal').then(module => ({ default: module.RevokeCollectionInclusionModal })),
|
'REVOKE_COLLECTION_INCLUSION': () => import('@/mastodon/features/collections/detail/revoke_collection_inclusion_modal').then(module => ({ default: module.RevokeCollectionInclusionModal })),
|
||||||
'ACTIONS': () => Promise.resolve({ default: ActionsModal }),
|
'ACTIONS': () => Promise.resolve({ default: ActionsModal }),
|
||||||
'EMBED': EmbedModal,
|
'EMBED': EmbedModal,
|
||||||
@ -105,6 +105,7 @@ export const MODAL_COMPONENTS = {
|
|||||||
'ACCOUNT_EDIT_IMAGE_ALT': accountEditModal('ImageAltModal'),
|
'ACCOUNT_EDIT_IMAGE_ALT': accountEditModal('ImageAltModal'),
|
||||||
'ACCOUNT_EDIT_IMAGE_DELETE': accountEditModal('ImageDeleteModal'),
|
'ACCOUNT_EDIT_IMAGE_DELETE': accountEditModal('ImageDeleteModal'),
|
||||||
'ACCOUNT_EDIT_IMAGE_UPLOAD': accountEditModal('ImageUploadModal'),
|
'ACCOUNT_EDIT_IMAGE_UPLOAD': accountEditModal('ImageUploadModal'),
|
||||||
|
'ACCOUNT_HIDE_FEATURED_TAB': () => import('@/mastodon/features/ui/components/confirmation_modals/hide_featured_tab').then(module => ({ default: module.ConfirmHideFeaturedTabModal })),
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @arg {keyof import('@/mastodon/features/account_edit/modals')} type */
|
/** @arg {keyof import('@/mastodon/features/account_edit/modals')} type */
|
||||||
|
|||||||
@ -232,6 +232,13 @@ class SwitchingColumnsArea extends PureComponent {
|
|||||||
|
|
||||||
<WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} />
|
<WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} />
|
||||||
<WrappedRoute path={['/@:acct/featured', '/accounts/:id/featured']} component={AccountFeatured} content={children} />
|
<WrappedRoute path={['/@:acct/featured', '/accounts/:id/featured']} component={AccountFeatured} content={children} />
|
||||||
|
{areCollectionsEnabled() &&
|
||||||
|
[
|
||||||
|
<WrappedRoute path={['/@:acct/collections']} component={Collections} content={children} key='collections-list' />,
|
||||||
|
<WrappedRoute path={['/collections/new', '/collections/:id/edit']} component={CollectionsEditor} content={children} key='collections-editor' />,
|
||||||
|
<WrappedRoute path='/collections/:id' component={CollectionDetail} content={children} key='collections-detail' />,
|
||||||
|
]
|
||||||
|
}
|
||||||
<WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} />
|
<WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} />
|
||||||
<WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />
|
<WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />
|
||||||
<WrappedRoute path={['/accounts/:id/followers', '/users/:acct/followers', '/@:acct/followers']} component={Followers} content={children} />
|
<WrappedRoute path={['/accounts/:id/followers', '/users/:acct/followers', '/@:acct/followers']} component={Followers} content={children} />
|
||||||
@ -255,13 +262,6 @@ class SwitchingColumnsArea extends PureComponent {
|
|||||||
<WrappedRoute path='/followed_tags' component={FollowedTags} content={children} />
|
<WrappedRoute path='/followed_tags' component={FollowedTags} content={children} />
|
||||||
<WrappedRoute path='/mutes' component={Mutes} content={children} />
|
<WrappedRoute path='/mutes' component={Mutes} content={children} />
|
||||||
<WrappedRoute path='/lists' component={Lists} content={children} />
|
<WrappedRoute path='/lists' component={Lists} content={children} />
|
||||||
{areCollectionsEnabled() &&
|
|
||||||
[
|
|
||||||
<WrappedRoute path={['/collections/new', '/collections/:id/edit']} component={CollectionsEditor} content={children} key='collections-editor' />,
|
|
||||||
<WrappedRoute path='/collections/:id' component={CollectionDetail} content={children} key='collections-detail' />,
|
|
||||||
<WrappedRoute path='/collections' component={Collections} content={children} key='collections-list' />
|
|
||||||
]
|
|
||||||
}
|
|
||||||
<Route component={BundleColumnError} />
|
<Route component={BundleColumnError} />
|
||||||
</WrappedSwitch>
|
</WrappedSwitch>
|
||||||
</ColumnsArea>
|
</ColumnsArea>
|
||||||
|
|||||||
@ -31,6 +31,7 @@
|
|||||||
"account.disable_notifications": "توقف عن إشعاري عندما ينشر @{name}",
|
"account.disable_notifications": "توقف عن إشعاري عندما ينشر @{name}",
|
||||||
"account.domain_blocking": "نطاق محظور",
|
"account.domain_blocking": "نطاق محظور",
|
||||||
"account.edit_profile": "تعديل الملف الشخصي",
|
"account.edit_profile": "تعديل الملف الشخصي",
|
||||||
|
"account.edit_profile_short": "تعديل",
|
||||||
"account.enable_notifications": "أشعرني عندما ينشر @{name}",
|
"account.enable_notifications": "أشعرني عندما ينشر @{name}",
|
||||||
"account.endorse": "أوصِ به على صفحتك الشخصية",
|
"account.endorse": "أوصِ به على صفحتك الشخصية",
|
||||||
"account.familiar_followers_many": "يتبعه {name1}، {name2} و{othersCount, plural, one {شخص آخر تعرفه} other {# أشخاص آخرون تعرفهم}}",
|
"account.familiar_followers_many": "يتبعه {name1}، {name2} و{othersCount, plural, one {شخص آخر تعرفه} other {# أشخاص آخرون تعرفهم}}",
|
||||||
@ -97,6 +98,27 @@
|
|||||||
"account.unmute": "إلغاء الكَتم عن @{name}",
|
"account.unmute": "إلغاء الكَتم عن @{name}",
|
||||||
"account.unmute_notifications_short": "إلغاء كَتم الإشعارات",
|
"account.unmute_notifications_short": "إلغاء كَتم الإشعارات",
|
||||||
"account.unmute_short": "إلغاء الكتم",
|
"account.unmute_short": "إلغاء الكتم",
|
||||||
|
"account_edit.bio.add_label": "إضافة سيرة ذاتية",
|
||||||
|
"account_edit.bio_modal.add_title": "إضافة سيرة ذاتية",
|
||||||
|
"account_edit.custom_fields.add_label": "إضافة حقل",
|
||||||
|
"account_edit.field_actions.edit": "تعديل الحقل",
|
||||||
|
"account_edit.field_delete_modal.delete_button": "حذف",
|
||||||
|
"account_edit.field_edit_modal.value_label": "قيمة",
|
||||||
|
"account_edit.image_alt_modal.text_label": "نص بديل",
|
||||||
|
"account_edit.image_delete_modal.delete_button": "حذف",
|
||||||
|
"account_edit.image_edit.add_button": "إضافة صورة",
|
||||||
|
"account_edit.image_edit.alt_add_button": "إضافة نص بديل",
|
||||||
|
"account_edit.save": "حفظ",
|
||||||
|
"account_edit.upload_modal.back": "العودة",
|
||||||
|
"account_edit.upload_modal.done": "تمّ",
|
||||||
|
"account_edit.upload_modal.next": "التالي",
|
||||||
|
"account_edit.upload_modal.step_upload.dragging": "إسقاط للتحميل",
|
||||||
|
"account_edit.upload_modal.step_upload.header": "اختيار صورة",
|
||||||
|
"account_edit.upload_modal.title_add.avatar": "إضافة صورة الملف الشخصي",
|
||||||
|
"account_edit.upload_modal.title_add.header": "إضافة صورة الغلاف",
|
||||||
|
"account_edit.upload_modal.title_replace.avatar": "استبدال صورة الملف الشخصي",
|
||||||
|
"account_edit.upload_modal.title_replace.header": "استبدال صورة الغلاف",
|
||||||
|
"account_edit_tags.add_tag": "إضافة #{tagName}",
|
||||||
"account_note.placeholder": "اضغط لإضافة مُلاحظة",
|
"account_note.placeholder": "اضغط لإضافة مُلاحظة",
|
||||||
"admin.dashboard.daily_retention": "معدّل بقاء المستخدمين بعد إنشاء الحسابات، بالأيام",
|
"admin.dashboard.daily_retention": "معدّل بقاء المستخدمين بعد إنشاء الحسابات، بالأيام",
|
||||||
"admin.dashboard.monthly_retention": "معدّل بقاء المستخدمين بعد إنشاء الحسابات، بالشهور",
|
"admin.dashboard.monthly_retention": "معدّل بقاء المستخدمين بعد إنشاء الحسابات، بالشهور",
|
||||||
@ -120,6 +142,9 @@
|
|||||||
"alt_text_modal.describe_for_people_with_visual_impairments": "قم بوصفها للأشخاص ذوي الإعاقة البصرية…",
|
"alt_text_modal.describe_for_people_with_visual_impairments": "قم بوصفها للأشخاص ذوي الإعاقة البصرية…",
|
||||||
"alt_text_modal.done": "تمّ",
|
"alt_text_modal.done": "تمّ",
|
||||||
"announcement.announcement": "إعلان",
|
"announcement.announcement": "إعلان",
|
||||||
|
"annual_report.announcement.action_dismiss": "لا شكراً",
|
||||||
|
"annual_report.nav_item.badge": "جديد",
|
||||||
|
"annual_report.shared_page.donate": "تبرع",
|
||||||
"annual_report.summary.archetype.replier.name": "الفراشة",
|
"annual_report.summary.archetype.replier.name": "الفراشة",
|
||||||
"annual_report.summary.close": "اغلق",
|
"annual_report.summary.close": "اغلق",
|
||||||
"annual_report.summary.copy_link": "نسخ الرابط",
|
"annual_report.summary.copy_link": "نسخ الرابط",
|
||||||
@ -162,11 +187,15 @@
|
|||||||
"closed_registrations_modal.preamble": "ماستدون لامركزي، لذلك بغض النظر عن مكان إنشاء حسابك، سيكون بإمكانك المتابعة والتفاعل مع أي شخص على هذا الخادم. يمكنك حتى أن تستضيفه ذاتياً!",
|
"closed_registrations_modal.preamble": "ماستدون لامركزي، لذلك بغض النظر عن مكان إنشاء حسابك، سيكون بإمكانك المتابعة والتفاعل مع أي شخص على هذا الخادم. يمكنك حتى أن تستضيفه ذاتياً!",
|
||||||
"closed_registrations_modal.title": "إنشاء حساب على ماستدون",
|
"closed_registrations_modal.title": "إنشاء حساب على ماستدون",
|
||||||
"collections.collection_description": "الوصف",
|
"collections.collection_description": "الوصف",
|
||||||
|
"collections.collection_language": "اللغة",
|
||||||
"collections.collection_name": "الاسم",
|
"collections.collection_name": "الاسم",
|
||||||
"collections.collection_topic": "الموضوع",
|
"collections.collection_topic": "الموضوع",
|
||||||
"collections.content_warning": "تحذير عن المحتوى",
|
"collections.content_warning": "تحذير عن المحتوى",
|
||||||
"collections.continue": "مواصلة",
|
"collections.continue": "مواصلة",
|
||||||
"collections.create.steps": "الخطوة {step}/{total}",
|
"collections.create.steps": "الخطوة {step}/{total}",
|
||||||
|
"collections.detail.accounts_heading": "الحسابات",
|
||||||
|
"collections.detail.sensitive_content": "محتوى حساس",
|
||||||
|
"collections.edit_details": "تعديل التفاصيل",
|
||||||
"collections.manage_accounts": "إدارة الحسابات",
|
"collections.manage_accounts": "إدارة الحسابات",
|
||||||
"column.about": "عن",
|
"column.about": "عن",
|
||||||
"column.blocks": "المُستَخدِمون المَحظورون",
|
"column.blocks": "المُستَخدِمون المَحظورون",
|
||||||
@ -195,6 +224,9 @@
|
|||||||
"column_header.show_settings": "إظهار الإعدادات",
|
"column_header.show_settings": "إظهار الإعدادات",
|
||||||
"column_header.unpin": "إلغاء التَّثبيت",
|
"column_header.unpin": "إلغاء التَّثبيت",
|
||||||
"column_search.cancel": "إلغاء",
|
"column_search.cancel": "إلغاء",
|
||||||
|
"combobox.close_results": "إغلاق النتائج",
|
||||||
|
"combobox.loading": "جاري التحميل",
|
||||||
|
"combobox.open_results": "فتح النتائج",
|
||||||
"community.column_settings.local_only": "المحلي فقط",
|
"community.column_settings.local_only": "المحلي فقط",
|
||||||
"community.column_settings.media_only": "الوسائط فقط",
|
"community.column_settings.media_only": "الوسائط فقط",
|
||||||
"community.column_settings.remote_only": "عن بُعد فقط",
|
"community.column_settings.remote_only": "عن بُعد فقط",
|
||||||
@ -268,11 +300,13 @@
|
|||||||
"content_warning.hide": "إخفاء المنشور",
|
"content_warning.hide": "إخفاء المنشور",
|
||||||
"content_warning.show": "إظهار على أي حال",
|
"content_warning.show": "إظهار على أي حال",
|
||||||
"content_warning.show_more": "إظهار المزيد",
|
"content_warning.show_more": "إظهار المزيد",
|
||||||
|
"content_warning.show_short": "إظهار",
|
||||||
"conversation.delete": "احذف المحادثة",
|
"conversation.delete": "احذف المحادثة",
|
||||||
"conversation.mark_as_read": "اعتبرها كمقروءة",
|
"conversation.mark_as_read": "اعتبرها كمقروءة",
|
||||||
"conversation.open": "اعرض المحادثة",
|
"conversation.open": "اعرض المحادثة",
|
||||||
"conversation.with": "مع {names}",
|
"conversation.with": "مع {names}",
|
||||||
"copy_icon_button.copied": "نُسِخ إلى الحافظة",
|
"copy_icon_button.copied": "نُسِخ إلى الحافظة",
|
||||||
|
"copy_icon_button.copy_this_text": "نسخ الرابط إلى الحافظة",
|
||||||
"copypaste.copied": "تم نسخه",
|
"copypaste.copied": "تم نسخه",
|
||||||
"copypaste.copy_to_clipboard": "نسخ إلى الحافظة",
|
"copypaste.copy_to_clipboard": "نسخ إلى الحافظة",
|
||||||
"directory.federated": "مِن الفديفرس المعروف",
|
"directory.federated": "مِن الفديفرس المعروف",
|
||||||
@ -307,6 +341,8 @@
|
|||||||
"domain_pill.your_server": "موطِنك الرقمي، حيث توجد فيه كافة منشوراتك. ألا يعجبك المكان؟ يمكنك الانتقال بين الخوادم في أي وقت واصطحاب متابعيك أيضاً.",
|
"domain_pill.your_server": "موطِنك الرقمي، حيث توجد فيه كافة منشوراتك. ألا يعجبك المكان؟ يمكنك الانتقال بين الخوادم في أي وقت واصطحاب متابعيك أيضاً.",
|
||||||
"domain_pill.your_username": "معرفك الفريد على هذا الخادم. من الممكن العثور على مستخدمين بنفس إسم المستخدم على خوادم مختلفة.",
|
"domain_pill.your_username": "معرفك الفريد على هذا الخادم. من الممكن العثور على مستخدمين بنفس إسم المستخدم على خوادم مختلفة.",
|
||||||
"dropdown.empty": "حدد خيارا",
|
"dropdown.empty": "حدد خيارا",
|
||||||
|
"email_subscriptions.email": "البريد الإلكتروني",
|
||||||
|
"email_subscriptions.form.action": "اشترك",
|
||||||
"embed.instructions": "يمكنكم إدماج هذا المنشور على موقعكم الإلكتروني عن طريق نسخ الشفرة أدناه.",
|
"embed.instructions": "يمكنكم إدماج هذا المنشور على موقعكم الإلكتروني عن طريق نسخ الشفرة أدناه.",
|
||||||
"embed.preview": "إليك ما سيبدو عليه:",
|
"embed.preview": "إليك ما سيبدو عليه:",
|
||||||
"emoji_button.activity": "الأنشطة",
|
"emoji_button.activity": "الأنشطة",
|
||||||
@ -324,7 +360,6 @@
|
|||||||
"emoji_button.search_results": "نتائج البحث",
|
"emoji_button.search_results": "نتائج البحث",
|
||||||
"emoji_button.symbols": "رموز",
|
"emoji_button.symbols": "رموز",
|
||||||
"emoji_button.travel": "الأماكن والسفر",
|
"emoji_button.travel": "الأماكن والسفر",
|
||||||
"empty_column.account_featured.other": "{acct} لم يعرض أي شيء حتى الآن. هل تعلم أنه يمكنك عرض الهاشتاقات التي تستخدمها، وحتى حسابات أصدقاءك على ملفك الشخصي؟",
|
|
||||||
"empty_column.account_hides_collections": "اختار هذا المستخدم عدم إتاحة هذه المعلومات للعامة",
|
"empty_column.account_hides_collections": "اختار هذا المستخدم عدم إتاحة هذه المعلومات للعامة",
|
||||||
"empty_column.account_suspended": "حساب معلق",
|
"empty_column.account_suspended": "حساب معلق",
|
||||||
"empty_column.account_timeline": "لا توجد منشورات هنا!",
|
"empty_column.account_timeline": "لا توجد منشورات هنا!",
|
||||||
@ -346,6 +381,7 @@
|
|||||||
"empty_column.notification_requests": "لا يوجد شيء هنا. عندما تتلقى إشعارات جديدة، سوف تظهر هنا وفقًا لإعداداتك.",
|
"empty_column.notification_requests": "لا يوجد شيء هنا. عندما تتلقى إشعارات جديدة، سوف تظهر هنا وفقًا لإعداداتك.",
|
||||||
"empty_column.notifications": "لم تتلق أي إشعار بعدُ. تفاعل مع المستخدمين الآخرين لإنشاء محادثة.",
|
"empty_column.notifications": "لم تتلق أي إشعار بعدُ. تفاعل مع المستخدمين الآخرين لإنشاء محادثة.",
|
||||||
"empty_column.public": "لا يوجد أي شيء هنا! قم بنشر شيء ما للعامة، أو اتبع المستخدمين الآخرين المتواجدين على الخوادم الأخرى لملء خيط المحادثات",
|
"empty_column.public": "لا يوجد أي شيء هنا! قم بنشر شيء ما للعامة، أو اتبع المستخدمين الآخرين المتواجدين على الخوادم الأخرى لملء خيط المحادثات",
|
||||||
|
"empty_state.no_results": "لا توجد نتائج",
|
||||||
"error.unexpected_crash.explanation": "نظرا لوجود خطأ في التعليمات البرمجية أو مشكلة توافق مع المتصفّح، تعذر عرض هذه الصفحة بشكل صحيح.",
|
"error.unexpected_crash.explanation": "نظرا لوجود خطأ في التعليمات البرمجية أو مشكلة توافق مع المتصفّح، تعذر عرض هذه الصفحة بشكل صحيح.",
|
||||||
"error.unexpected_crash.explanation_addons": "لا يمكن عرض هذه الصفحة بشكل صحيح. من المحتمل أن يكون هذا الخطأ بسبب إضافة متصفح أو أدوات ترجمة تلقائية.",
|
"error.unexpected_crash.explanation_addons": "لا يمكن عرض هذه الصفحة بشكل صحيح. من المحتمل أن يكون هذا الخطأ بسبب إضافة متصفح أو أدوات ترجمة تلقائية.",
|
||||||
"error.unexpected_crash.next_steps": "حاول إعادة إنعاش الصفحة. إن لم تُحلّ المشكلة، يمكنك دائمًا استخدام ماستدون عبر متصفّح آخر أو تطبيق أصلي.",
|
"error.unexpected_crash.next_steps": "حاول إعادة إنعاش الصفحة. إن لم تُحلّ المشكلة، يمكنك دائمًا استخدام ماستدون عبر متصفّح آخر أو تطبيق أصلي.",
|
||||||
@ -358,6 +394,8 @@
|
|||||||
"explore.trending_statuses": "المنشورات",
|
"explore.trending_statuses": "المنشورات",
|
||||||
"explore.trending_tags": "وُسُوم",
|
"explore.trending_tags": "وُسُوم",
|
||||||
"featured_carousel.header": "{count, plural, zero {}one {منشور معروض} two {منشور معروضَين} few {منشورات معروضة} many {منشورات معروضة} other {منشورات معروضة}}",
|
"featured_carousel.header": "{count, plural, zero {}one {منشور معروض} two {منشور معروضَين} few {منشورات معروضة} many {منشورات معروضة} other {منشورات معروضة}}",
|
||||||
|
"featured_tags.suggestions.add": "إضافة",
|
||||||
|
"featured_tags.suggestions.dismiss": "لا شكراً",
|
||||||
"filter_modal.added.context_mismatch_explanation": "فئة عامل التصفية هذه لا تنطبق على السياق الذي وصلت فيه إلى هذه المشاركة. إذا كنت ترغب في تصفية المنشور في هذا السياق أيضا، فسيتعين عليك تعديل عامل التصفية.",
|
"filter_modal.added.context_mismatch_explanation": "فئة عامل التصفية هذه لا تنطبق على السياق الذي وصلت فيه إلى هذه المشاركة. إذا كنت ترغب في تصفية المنشور في هذا السياق أيضا، فسيتعين عليك تعديل عامل التصفية.",
|
||||||
"filter_modal.added.context_mismatch_title": "عدم تطابق السياق!",
|
"filter_modal.added.context_mismatch_title": "عدم تطابق السياق!",
|
||||||
"filter_modal.added.expired_explanation": "انتهت صلاحية فئة عامل التصفية هذه، سوف تحتاج إلى تغيير تاريخ انتهاء الصلاحية لتطبيقها.",
|
"filter_modal.added.expired_explanation": "انتهت صلاحية فئة عامل التصفية هذه، سوف تحتاج إلى تغيير تاريخ انتهاء الصلاحية لتطبيقها.",
|
||||||
@ -867,6 +905,8 @@
|
|||||||
"status.cancel_reblog_private": "إلغاء إعادة النشر",
|
"status.cancel_reblog_private": "إلغاء إعادة النشر",
|
||||||
"status.cannot_quote": "غير مصرح لك باقتباس هذا المنشور",
|
"status.cannot_quote": "غير مصرح لك باقتباس هذا المنشور",
|
||||||
"status.cannot_reblog": "لا يمكن إعادة نشر هذا المنشور",
|
"status.cannot_reblog": "لا يمكن إعادة نشر هذا المنشور",
|
||||||
|
"status.context.retry": "حاول مجددًا",
|
||||||
|
"status.context.show": "إظهار",
|
||||||
"status.continued_thread": "تكملة للخيط",
|
"status.continued_thread": "تكملة للخيط",
|
||||||
"status.copy": "انسخ رابط الرسالة",
|
"status.copy": "انسخ رابط الرسالة",
|
||||||
"status.delete": "احذف",
|
"status.delete": "احذف",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "Выбранае",
|
"account.featured": "Выбранае",
|
||||||
"account.featured.accounts": "Профілі",
|
"account.featured.accounts": "Профілі",
|
||||||
"account.featured.collections": "Калекцыі",
|
"account.featured.collections": "Калекцыі",
|
||||||
|
"account.featured.new_collection": "Новая калекцыя",
|
||||||
"account.field_overflow": "Паказаць усё змесціва",
|
"account.field_overflow": "Паказаць усё змесціва",
|
||||||
"account.filters.all": "Уся актыўнасць",
|
"account.filters.all": "Уся актыўнасць",
|
||||||
"account.filters.boosts_toggle": "Паказваць пашырэнні",
|
"account.filters.boosts_toggle": "Паказваць пашырэнні",
|
||||||
@ -416,7 +417,6 @@
|
|||||||
"column.about": "Пра нас",
|
"column.about": "Пра нас",
|
||||||
"column.blocks": "Заблакіраваныя карыстальнікі",
|
"column.blocks": "Заблакіраваныя карыстальнікі",
|
||||||
"column.bookmarks": "Закладкі",
|
"column.bookmarks": "Закладкі",
|
||||||
"column.collections": "Мае калекцыі",
|
|
||||||
"column.community": "Лакальная стужка",
|
"column.community": "Лакальная стужка",
|
||||||
"column.create_list": "Стварыць спіс",
|
"column.create_list": "Стварыць спіс",
|
||||||
"column.direct": "Прыватныя згадванні",
|
"column.direct": "Прыватныя згадванні",
|
||||||
@ -432,7 +432,9 @@
|
|||||||
"column.list_members": "Кіраванне ўдзельнікамі спіса",
|
"column.list_members": "Кіраванне ўдзельнікамі спіса",
|
||||||
"column.lists": "Спісы",
|
"column.lists": "Спісы",
|
||||||
"column.mutes": "Ігнараваныя карыстальнікі",
|
"column.mutes": "Ігнараваныя карыстальнікі",
|
||||||
|
"column.my_collections": "Мае калекцыі",
|
||||||
"column.notifications": "Апавяшчэнні",
|
"column.notifications": "Апавяшчэнні",
|
||||||
|
"column.other_collections": "Калекцыі {name}",
|
||||||
"column.pins": "Замацаваныя допісы",
|
"column.pins": "Замацаваныя допісы",
|
||||||
"column.public": "Інтэграваная стужка",
|
"column.public": "Інтэграваная стужка",
|
||||||
"column_back_button.label": "Назад",
|
"column_back_button.label": "Назад",
|
||||||
@ -502,6 +504,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Падпісацца і дадаць у спіс",
|
"confirmations.follow_to_list.confirm": "Падпісацца і дадаць у спіс",
|
||||||
"confirmations.follow_to_list.message": "Вам трэба падпісацца на {name}, каб дадаць яго/яе ў спіс.",
|
"confirmations.follow_to_list.message": "Вам трэба падпісацца на {name}, каб дадаць яго/яе ў спіс.",
|
||||||
"confirmations.follow_to_list.title": "Падпісацца на карыстальніка?",
|
"confirmations.follow_to_list.title": "Падпісацца на карыстальніка?",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Схаваць укладку",
|
||||||
|
"confirmations.hide_featured_tab.intro": "Вы можаце змяніць гэтую наладу ў любы момант у <i>Рэдагаваць профіль > Налады ўкладкі профілю</i>.",
|
||||||
|
"confirmations.hide_featured_tab.message": "Гэтае дзеянне схавае ўкладку ад карыстальнікаў {serverName} і іншых сервераў з апошняй версіяй Mastodon. Яе адлюстраванне на іншых серверах можа адрознівацца.",
|
||||||
|
"confirmations.hide_featured_tab.title": "Схаваць укладку \"Выбранае\"?",
|
||||||
"confirmations.logout.confirm": "Выйсці",
|
"confirmations.logout.confirm": "Выйсці",
|
||||||
"confirmations.logout.message": "Вы ўпэўненыя, што хочаце выйсці?",
|
"confirmations.logout.message": "Вы ўпэўненыя, што хочаце выйсці?",
|
||||||
"confirmations.logout.title": "Выйсці?",
|
"confirmations.logout.title": "Выйсці?",
|
||||||
@ -606,14 +612,13 @@
|
|||||||
"emoji_button.search_results": "Вынікі пошуку",
|
"emoji_button.search_results": "Вынікі пошуку",
|
||||||
"emoji_button.symbols": "Сімвалы",
|
"emoji_button.symbols": "Сімвалы",
|
||||||
"emoji_button.travel": "Падарожжы і месцы",
|
"emoji_button.travel": "Падарожжы і месцы",
|
||||||
"empty_column.account_featured.other": "{acct} яшчэ нічога не адабраў для паказу. Ці ведалі Вы, што ў сваім профілі Вы можаце паказаць свае хэштэгі, якімі найбольш карыстаецеся, і нават профілі сваіх сяброў?",
|
"empty_column.account_featured.other": "{acct} пакуль нічога не адабраў(-ла) для паказу.",
|
||||||
"empty_column.account_featured_other.no_collections_desc": "{acct} пакуль не стварыў(-ла) аніводнай калекцыі.",
|
|
||||||
"empty_column.account_featured_other.title": "Тут нічога няма",
|
|
||||||
"empty_column.account_featured_self.no_collections": "Пакуль няма калекцый",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Стварыць калекцыю",
|
"empty_column.account_featured_self.no_collections_button": "Стварыць калекцыю",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "Або схаваць гэтую ўкладку",
|
||||||
"empty_column.account_featured_self.pre_collections": "Рыхтуйцеся да Калекцый",
|
"empty_column.account_featured_self.pre_collections": "Рыхтуйцеся да Калекцый",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Калекцыі (новая функцыя Mastodon 4.6) дазволяць Вам ствараць свае ўласныя спісы ўліковых запісаў, каб раіць іх іншым.",
|
"empty_column.account_featured_self.pre_collections_desc": "Калекцыі (новая функцыя Mastodon 4.6) дазволяць Вам ствараць свае ўласныя спісы ўліковых запісаў, каб раіць іх іншым.",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Гэты ўліковы запіс пакуль не стварыў аніводнай калекцыі.",
|
"empty_column.account_featured_self.showcase_accounts": "Паказаць Вашыя ўлюбёныя ўліковыя запісы",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "Калекцыі — спісы адабраных уліковых запісаў, якія дапамагаюць іншым знаходзіць нешта новае ў федэральным сусвеце.",
|
||||||
"empty_column.account_featured_unknown.other": "Гэты ўліковы запіс пакуль нічога не адабраў для паказу.",
|
"empty_column.account_featured_unknown.other": "Гэты ўліковы запіс пакуль нічога не адабраў для паказу.",
|
||||||
"empty_column.account_hides_collections": "Гэты карыстальнік вырашыў схаваць гэтую інфармацыю",
|
"empty_column.account_hides_collections": "Гэты карыстальнік вырашыў схаваць гэтую інфармацыю",
|
||||||
"empty_column.account_suspended": "Уліковы запіс прыпынены",
|
"empty_column.account_suspended": "Уліковы запіс прыпынены",
|
||||||
|
|||||||
@ -219,7 +219,6 @@
|
|||||||
"column.about": "Quant a",
|
"column.about": "Quant a",
|
||||||
"column.blocks": "Usuaris blocats",
|
"column.blocks": "Usuaris blocats",
|
||||||
"column.bookmarks": "Marcadors",
|
"column.bookmarks": "Marcadors",
|
||||||
"column.collections": "Les meves coŀleccions",
|
|
||||||
"column.community": "Línia de temps local",
|
"column.community": "Línia de temps local",
|
||||||
"column.create_list": "Crea una llista",
|
"column.create_list": "Crea una llista",
|
||||||
"column.direct": "Mencions privades",
|
"column.direct": "Mencions privades",
|
||||||
@ -388,7 +387,6 @@
|
|||||||
"emoji_button.search_results": "Resultats de la cerca",
|
"emoji_button.search_results": "Resultats de la cerca",
|
||||||
"emoji_button.symbols": "Símbols",
|
"emoji_button.symbols": "Símbols",
|
||||||
"emoji_button.travel": "Viatges i llocs",
|
"emoji_button.travel": "Viatges i llocs",
|
||||||
"empty_column.account_featured.other": "{acct} encara no ha destacat res. Sabeu que podeu destacar les etiquetes que més feu servir i fins i tot els comptes dels vostres amics al vostre perfil?",
|
|
||||||
"empty_column.account_hides_collections": "Aquest usuari ha decidit no mostrar aquesta informació",
|
"empty_column.account_hides_collections": "Aquest usuari ha decidit no mostrar aquesta informació",
|
||||||
"empty_column.account_suspended": "Compte suspès",
|
"empty_column.account_suspended": "Compte suspès",
|
||||||
"empty_column.account_timeline": "No hi ha tuts aquí!",
|
"empty_column.account_timeline": "No hi ha tuts aquí!",
|
||||||
|
|||||||
@ -266,7 +266,6 @@
|
|||||||
"column.about": "O aplikaci",
|
"column.about": "O aplikaci",
|
||||||
"column.blocks": "Blokovaní uživatelé",
|
"column.blocks": "Blokovaní uživatelé",
|
||||||
"column.bookmarks": "Záložky",
|
"column.bookmarks": "Záložky",
|
||||||
"column.collections": "Mé sbírky",
|
|
||||||
"column.community": "Místní časová osa",
|
"column.community": "Místní časová osa",
|
||||||
"column.create_list": "Vytvořit seznam",
|
"column.create_list": "Vytvořit seznam",
|
||||||
"column.direct": "Soukromé zmínky",
|
"column.direct": "Soukromé zmínky",
|
||||||
@ -439,7 +438,6 @@
|
|||||||
"emoji_button.search_results": "Výsledky hledání",
|
"emoji_button.search_results": "Výsledky hledání",
|
||||||
"emoji_button.symbols": "Symboly",
|
"emoji_button.symbols": "Symboly",
|
||||||
"emoji_button.travel": "Cestování a místa",
|
"emoji_button.travel": "Cestování a místa",
|
||||||
"empty_column.account_featured.other": "{acct} zatím nic nezvýraznili. Věděli jste, že na svém profilu můžete zvýraznit hashtagy, které používáte nejvíce, a dokonce účty vašich přátel?",
|
|
||||||
"empty_column.account_hides_collections": "Tento uživatel se rozhodl tuto informaci nezveřejňovat",
|
"empty_column.account_hides_collections": "Tento uživatel se rozhodl tuto informaci nezveřejňovat",
|
||||||
"empty_column.account_suspended": "Účet je pozastaven",
|
"empty_column.account_suspended": "Účet je pozastaven",
|
||||||
"empty_column.account_timeline": "Nejsou tu žádné příspěvky!",
|
"empty_column.account_timeline": "Nejsou tu žádné příspěvky!",
|
||||||
|
|||||||
@ -383,7 +383,6 @@
|
|||||||
"column.about": "Ynghylch",
|
"column.about": "Ynghylch",
|
||||||
"column.blocks": "Defnyddwyr wedi'u rhwystro",
|
"column.blocks": "Defnyddwyr wedi'u rhwystro",
|
||||||
"column.bookmarks": "Llyfrnodau",
|
"column.bookmarks": "Llyfrnodau",
|
||||||
"column.collections": "Fy nghasgliadau",
|
|
||||||
"column.community": "Ffrwd lleol",
|
"column.community": "Ffrwd lleol",
|
||||||
"column.create_list": "Creu rhestr",
|
"column.create_list": "Creu rhestr",
|
||||||
"column.direct": "Crybwylliadau preifat",
|
"column.direct": "Crybwylliadau preifat",
|
||||||
@ -564,7 +563,6 @@
|
|||||||
"emoji_button.search_results": "Canlyniadau chwilio",
|
"emoji_button.search_results": "Canlyniadau chwilio",
|
||||||
"emoji_button.symbols": "Symbolau",
|
"emoji_button.symbols": "Symbolau",
|
||||||
"emoji_button.travel": "Teithio a Llefydd",
|
"emoji_button.travel": "Teithio a Llefydd",
|
||||||
"empty_column.account_featured.other": "Dyw {acct} heb gynnwys unrhyw beth eto. Oeddech chi'n gwybod y gallwch chi gynnwys yr hashnodau rydych chi'n eu defnyddio fwyaf, a hyd yn oed cyfrifon eich ffrindiau ar eich proffil?",
|
|
||||||
"empty_column.account_hides_collections": "Mae'r defnyddiwr wedi dewis i beidio rhannu'r wybodaeth yma",
|
"empty_column.account_hides_collections": "Mae'r defnyddiwr wedi dewis i beidio rhannu'r wybodaeth yma",
|
||||||
"empty_column.account_suspended": "Cyfrif wedi'i atal",
|
"empty_column.account_suspended": "Cyfrif wedi'i atal",
|
||||||
"empty_column.account_timeline": "Dim postiadau yma!",
|
"empty_column.account_timeline": "Dim postiadau yma!",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "Fremhævet",
|
"account.featured": "Fremhævet",
|
||||||
"account.featured.accounts": "Profiler",
|
"account.featured.accounts": "Profiler",
|
||||||
"account.featured.collections": "Samlinger",
|
"account.featured.collections": "Samlinger",
|
||||||
|
"account.featured.new_collection": "Ny samling",
|
||||||
"account.field_overflow": "Vis fuldt indhold",
|
"account.field_overflow": "Vis fuldt indhold",
|
||||||
"account.filters.all": "Al aktivitet",
|
"account.filters.all": "Al aktivitet",
|
||||||
"account.filters.boosts_toggle": "Vis fremhævelser",
|
"account.filters.boosts_toggle": "Vis fremhævelser",
|
||||||
@ -416,7 +417,6 @@
|
|||||||
"column.about": "Om",
|
"column.about": "Om",
|
||||||
"column.blocks": "Blokerede brugere",
|
"column.blocks": "Blokerede brugere",
|
||||||
"column.bookmarks": "Bogmærker",
|
"column.bookmarks": "Bogmærker",
|
||||||
"column.collections": "Mine samlinger",
|
|
||||||
"column.community": "Lokal tidslinje",
|
"column.community": "Lokal tidslinje",
|
||||||
"column.create_list": "Opret liste",
|
"column.create_list": "Opret liste",
|
||||||
"column.direct": "Private omtaler",
|
"column.direct": "Private omtaler",
|
||||||
@ -432,7 +432,9 @@
|
|||||||
"column.list_members": "Håndtér listemedlemmer",
|
"column.list_members": "Håndtér listemedlemmer",
|
||||||
"column.lists": "Lister",
|
"column.lists": "Lister",
|
||||||
"column.mutes": "Skjulte brugere",
|
"column.mutes": "Skjulte brugere",
|
||||||
|
"column.my_collections": "Mine samlinger",
|
||||||
"column.notifications": "Notifikationer",
|
"column.notifications": "Notifikationer",
|
||||||
|
"column.other_collections": "Samlinger af {name}",
|
||||||
"column.pins": "Fastgjorte indlæg",
|
"column.pins": "Fastgjorte indlæg",
|
||||||
"column.public": "Fælles tidslinje",
|
"column.public": "Fælles tidslinje",
|
||||||
"column_back_button.label": "Tilbage",
|
"column_back_button.label": "Tilbage",
|
||||||
@ -502,6 +504,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Følg og føj til liste",
|
"confirmations.follow_to_list.confirm": "Følg og føj til liste",
|
||||||
"confirmations.follow_to_list.message": "Du skal følge {name} for at føje vedkommende til en liste.",
|
"confirmations.follow_to_list.message": "Du skal følge {name} for at føje vedkommende til en liste.",
|
||||||
"confirmations.follow_to_list.title": "Følg bruger?",
|
"confirmations.follow_to_list.title": "Følg bruger?",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Skjul fane",
|
||||||
|
"confirmations.hide_featured_tab.intro": "Du kan til enhver tid ændre dette under <i>Rediger profil > Indstillinger for profil-fane</i>.",
|
||||||
|
"confirmations.hide_featured_tab.message": "Dette vil skjule fanen for brugere på {serverName} og andre servere, der kører den nyeste version af Mastodon. Andre visninger kan variere.",
|
||||||
|
"confirmations.hide_featured_tab.title": "Skjul fanen \"Fremhævet\"?",
|
||||||
"confirmations.logout.confirm": "Log ud",
|
"confirmations.logout.confirm": "Log ud",
|
||||||
"confirmations.logout.message": "Er du sikker på, at du vil logge ud?",
|
"confirmations.logout.message": "Er du sikker på, at du vil logge ud?",
|
||||||
"confirmations.logout.title": "Log ud?",
|
"confirmations.logout.title": "Log ud?",
|
||||||
@ -606,14 +612,13 @@
|
|||||||
"emoji_button.search_results": "Søgeresultater",
|
"emoji_button.search_results": "Søgeresultater",
|
||||||
"emoji_button.symbols": "Symboler",
|
"emoji_button.symbols": "Symboler",
|
||||||
"emoji_button.travel": "Rejser og steder",
|
"emoji_button.travel": "Rejser og steder",
|
||||||
"empty_column.account_featured.other": "{acct} har ikke fremhævet noget endnu. Vidste du, at du kan fremhæve dine mest brugte hashtags og endda din vens konti på din profil?",
|
"empty_column.account_featured.other": "{acct} har ikke fremhævet noget endnu.",
|
||||||
"empty_column.account_featured_other.no_collections_desc": "{acct} har endnu ikke oprettet nogen samlinger.",
|
|
||||||
"empty_column.account_featured_other.title": "Intet at se her",
|
|
||||||
"empty_column.account_featured_self.no_collections": "Ingen samlinger endnu",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Opret en samling",
|
"empty_column.account_featured_self.no_collections_button": "Opret en samling",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "Skjul denne fane i stedet",
|
||||||
"empty_column.account_featured_self.pre_collections": "Hold udkig efter Samlinger",
|
"empty_column.account_featured_self.pre_collections": "Hold udkig efter Samlinger",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Med samlinger (kommer i Mastodon 4.6) kan du oprette dine egne kuraterede lister over konti, som du kan anbefale til andre.",
|
"empty_column.account_featured_self.pre_collections_desc": "Med samlinger (kommer i Mastodon 4.6) kan du oprette dine egne kuraterede lister over konti, som du kan anbefale til andre.",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Denne konto har endnu ikke oprettet nogen samlinger.",
|
"empty_column.account_featured_self.showcase_accounts": "Vis dine favoritkonti",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "Samlinger er kuraterede lister over konti, der skal hjælpe andre med at opdage mere af Fediverset.",
|
||||||
"empty_column.account_featured_unknown.other": "Denne konto har ikke fremhævet noget endnu.",
|
"empty_column.account_featured_unknown.other": "Denne konto har ikke fremhævet noget endnu.",
|
||||||
"empty_column.account_hides_collections": "Brugeren har valgt ikke at gøre denne information tilgængelig",
|
"empty_column.account_hides_collections": "Brugeren har valgt ikke at gøre denne information tilgængelig",
|
||||||
"empty_column.account_suspended": "Konto suspenderet",
|
"empty_column.account_suspended": "Konto suspenderet",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "Vorgestellt",
|
"account.featured": "Vorgestellt",
|
||||||
"account.featured.accounts": "Profile",
|
"account.featured.accounts": "Profile",
|
||||||
"account.featured.collections": "Sammlungen",
|
"account.featured.collections": "Sammlungen",
|
||||||
|
"account.featured.new_collection": "Neue Sammlung",
|
||||||
"account.field_overflow": "Vollständigen Inhalt anzeigen",
|
"account.field_overflow": "Vollständigen Inhalt anzeigen",
|
||||||
"account.filters.all": "Alle Aktivitäten",
|
"account.filters.all": "Alle Aktivitäten",
|
||||||
"account.filters.boosts_toggle": "Geteilte Beiträge anzeigen",
|
"account.filters.boosts_toggle": "Geteilte Beiträge anzeigen",
|
||||||
@ -416,7 +417,6 @@
|
|||||||
"column.about": "Über",
|
"column.about": "Über",
|
||||||
"column.blocks": "Blockierte Profile",
|
"column.blocks": "Blockierte Profile",
|
||||||
"column.bookmarks": "Lesezeichen",
|
"column.bookmarks": "Lesezeichen",
|
||||||
"column.collections": "Meine Sammlungen",
|
|
||||||
"column.community": "Lokale Timeline",
|
"column.community": "Lokale Timeline",
|
||||||
"column.create_list": "Liste erstellen",
|
"column.create_list": "Liste erstellen",
|
||||||
"column.direct": "Private Erwähnungen",
|
"column.direct": "Private Erwähnungen",
|
||||||
@ -432,7 +432,9 @@
|
|||||||
"column.list_members": "Listenmitglieder verwalten",
|
"column.list_members": "Listenmitglieder verwalten",
|
||||||
"column.lists": "Listen",
|
"column.lists": "Listen",
|
||||||
"column.mutes": "Stummgeschaltete Profile",
|
"column.mutes": "Stummgeschaltete Profile",
|
||||||
|
"column.my_collections": "Meine Sammlungen",
|
||||||
"column.notifications": "Benachrichtigungen",
|
"column.notifications": "Benachrichtigungen",
|
||||||
|
"column.other_collections": "Sammlungen von {name}",
|
||||||
"column.pins": "Angeheftete Beiträge",
|
"column.pins": "Angeheftete Beiträge",
|
||||||
"column.public": "Föderierte Timeline",
|
"column.public": "Föderierte Timeline",
|
||||||
"column_back_button.label": "Zurück",
|
"column_back_button.label": "Zurück",
|
||||||
@ -502,6 +504,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Folgen und zur Liste hinzufügen",
|
"confirmations.follow_to_list.confirm": "Folgen und zur Liste hinzufügen",
|
||||||
"confirmations.follow_to_list.message": "Du musst {name} folgen, um das Profil zu einer Liste hinzufügen zu können.",
|
"confirmations.follow_to_list.message": "Du musst {name} folgen, um das Profil zu einer Liste hinzufügen zu können.",
|
||||||
"confirmations.follow_to_list.title": "Profil folgen?",
|
"confirmations.follow_to_list.title": "Profil folgen?",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Tab ausblenden",
|
||||||
|
"confirmations.hide_featured_tab.intro": "Du kannst die Einstellungen jederzeit unter <i>Profil bearbeiten > Profil-Tab-Einstellungen</i> ändern.",
|
||||||
|
"confirmations.hide_featured_tab.message": "Dieser Tab wird auf {serverName} und anderen Servern mit der neuesten Mastodon-Version nicht angezeigt. Darstellung kann darüber hinaus abweichen.",
|
||||||
|
"confirmations.hide_featured_tab.title": "„Vorgestellt“-Tab ausblenden?",
|
||||||
"confirmations.logout.confirm": "Abmelden",
|
"confirmations.logout.confirm": "Abmelden",
|
||||||
"confirmations.logout.message": "Möchtest du dich wirklich ausloggen?",
|
"confirmations.logout.message": "Möchtest du dich wirklich ausloggen?",
|
||||||
"confirmations.logout.title": "Abmelden?",
|
"confirmations.logout.title": "Abmelden?",
|
||||||
@ -606,14 +612,13 @@
|
|||||||
"emoji_button.search_results": "Suchergebnisse",
|
"emoji_button.search_results": "Suchergebnisse",
|
||||||
"emoji_button.symbols": "Symbole",
|
"emoji_button.symbols": "Symbole",
|
||||||
"emoji_button.travel": "Reisen & Orte",
|
"emoji_button.travel": "Reisen & Orte",
|
||||||
"empty_column.account_featured.other": "{acct} hat bisher noch nichts vorgestellt. Wusstest du, dass du deine häufig verwendeten Hashtags und sogar Profile von Freund*innen vorstellen kannst?",
|
"empty_column.account_featured.other": "{acct} hat noch nichts vorgestellt.",
|
||||||
"empty_column.account_featured_other.no_collections_desc": "{acct} hat noch keine Sammlungen erstellt.",
|
|
||||||
"empty_column.account_featured_other.title": "Hier gibt es nichts zu sehen",
|
|
||||||
"empty_column.account_featured_self.no_collections": "Noch keine Sammlungen",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Sammlung erstellen",
|
"empty_column.account_featured_self.no_collections_button": "Sammlung erstellen",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "Diesen Tab ausblenden",
|
||||||
"empty_column.account_featured_self.pre_collections": "Sammlungen sind bald verfügbar",
|
"empty_column.account_featured_self.pre_collections": "Sammlungen sind bald verfügbar",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Mit Sammlungen (neue Funktion in Mastodon 4.6) kannst du deine eigenen kuratierten Listen erstellen, um ausgewählte Konten zu empfehlen.",
|
"empty_column.account_featured_self.pre_collections_desc": "Mit Sammlungen (neue Funktion in Mastodon 4.6) kannst du deine eigenen kuratierten Listen erstellen, um ausgewählte Konten zu empfehlen.",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Dieser Account hat noch keine Sammlungen erstellt.",
|
"empty_column.account_featured_self.showcase_accounts": "Präsentiere deine liebsten Konten",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "Sammlungen sind kuratierte Listen, die anderen helfen, mehr Konten im Fediverse zu entdecken.",
|
||||||
"empty_column.account_featured_unknown.other": "Dieser Account hat noch nichts vorgestellt.",
|
"empty_column.account_featured_unknown.other": "Dieser Account hat noch nichts vorgestellt.",
|
||||||
"empty_column.account_hides_collections": "Das Profil hat sich entschieden, diese Information nicht zu veröffentlichen",
|
"empty_column.account_hides_collections": "Das Profil hat sich entschieden, diese Information nicht zu veröffentlichen",
|
||||||
"empty_column.account_suspended": "Konto dauerhaft gesperrt",
|
"empty_column.account_suspended": "Konto dauerhaft gesperrt",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "Αναδεδειγμένα",
|
"account.featured": "Αναδεδειγμένα",
|
||||||
"account.featured.accounts": "Προφίλ",
|
"account.featured.accounts": "Προφίλ",
|
||||||
"account.featured.collections": "Συλλογές",
|
"account.featured.collections": "Συλλογές",
|
||||||
|
"account.featured.new_collection": "Νέα συλλογή",
|
||||||
"account.field_overflow": "Εμφάνιση πλήρους περιεχομένου",
|
"account.field_overflow": "Εμφάνιση πλήρους περιεχομένου",
|
||||||
"account.filters.all": "Όλη η δραστηριότητα",
|
"account.filters.all": "Όλη η δραστηριότητα",
|
||||||
"account.filters.boosts_toggle": "Εμφάνιση ενισχύσεων",
|
"account.filters.boosts_toggle": "Εμφάνιση ενισχύσεων",
|
||||||
@ -217,7 +218,7 @@
|
|||||||
"account_edit.profile_tab.show_media_replies.description": "Όταν ενεργοποιηθεί, η καρτέλα Πολυμέσα εμφανίζει τόσο τις αναρτήσεις σας όσο και τις απαντήσεις σας σε αναρτήσεις άλλων ατόμων.",
|
"account_edit.profile_tab.show_media_replies.description": "Όταν ενεργοποιηθεί, η καρτέλα Πολυμέσα εμφανίζει τόσο τις αναρτήσεις σας όσο και τις απαντήσεις σας σε αναρτήσεις άλλων ατόμων.",
|
||||||
"account_edit.profile_tab.show_media_replies.title": "Συμπερίληψη απαντήσεων στην καρτέλα «Πολυμέσα»",
|
"account_edit.profile_tab.show_media_replies.title": "Συμπερίληψη απαντήσεων στην καρτέλα «Πολυμέσα»",
|
||||||
"account_edit.profile_tab.subtitle": "Προσαρμόστε τις καρτέλες στο προφίλ σας και τι εμφανίζουν.",
|
"account_edit.profile_tab.subtitle": "Προσαρμόστε τις καρτέλες στο προφίλ σας και τι εμφανίζουν.",
|
||||||
"account_edit.profile_tab.title": "Ρυθμίσεις καρτέλας προφίλ",
|
"account_edit.profile_tab.title": "Ρυθμίσεις καρτελών προφίλ",
|
||||||
"account_edit.save": "Αποθήκευση",
|
"account_edit.save": "Αποθήκευση",
|
||||||
"account_edit.upload_modal.back": "Πίσω",
|
"account_edit.upload_modal.back": "Πίσω",
|
||||||
"account_edit.upload_modal.done": "Έγινε",
|
"account_edit.upload_modal.done": "Έγινε",
|
||||||
@ -416,7 +417,6 @@
|
|||||||
"column.about": "Σχετικά με",
|
"column.about": "Σχετικά με",
|
||||||
"column.blocks": "Αποκλεισμένοι χρήστες",
|
"column.blocks": "Αποκλεισμένοι χρήστες",
|
||||||
"column.bookmarks": "Σελιδοδείκτες",
|
"column.bookmarks": "Σελιδοδείκτες",
|
||||||
"column.collections": "Οι συλλογές μου",
|
|
||||||
"column.community": "Τοπική ροή",
|
"column.community": "Τοπική ροή",
|
||||||
"column.create_list": "Δημιουργία λίστας",
|
"column.create_list": "Δημιουργία λίστας",
|
||||||
"column.direct": "Ιδιωτικές επισημάνσεις",
|
"column.direct": "Ιδιωτικές επισημάνσεις",
|
||||||
@ -432,7 +432,9 @@
|
|||||||
"column.list_members": "Διαχείριση μελών λίστας",
|
"column.list_members": "Διαχείριση μελών λίστας",
|
||||||
"column.lists": "Λίστες",
|
"column.lists": "Λίστες",
|
||||||
"column.mutes": "Αποσιωπημένοι χρήστες",
|
"column.mutes": "Αποσιωπημένοι χρήστες",
|
||||||
|
"column.my_collections": "Οι συλλογές μου",
|
||||||
"column.notifications": "Ειδοποιήσεις",
|
"column.notifications": "Ειδοποιήσεις",
|
||||||
|
"column.other_collections": "Συλλογές από {name}",
|
||||||
"column.pins": "Καρφιτσωμένες αναρτήσεις",
|
"column.pins": "Καρφιτσωμένες αναρτήσεις",
|
||||||
"column.public": "Ομοσπονδιακή ροή",
|
"column.public": "Ομοσπονδιακή ροή",
|
||||||
"column_back_button.label": "Πίσω",
|
"column_back_button.label": "Πίσω",
|
||||||
@ -502,6 +504,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Ακολούθησε και πρόσθεσε στη λίστα",
|
"confirmations.follow_to_list.confirm": "Ακολούθησε και πρόσθεσε στη λίστα",
|
||||||
"confirmations.follow_to_list.message": "Πρέπει να ακολουθήσεις τον χρήστη {name} για να τον προσθέσεις σε μια λίστα.",
|
"confirmations.follow_to_list.message": "Πρέπει να ακολουθήσεις τον χρήστη {name} για να τον προσθέσεις σε μια λίστα.",
|
||||||
"confirmations.follow_to_list.title": "Ακολούθηση χρήστη;",
|
"confirmations.follow_to_list.title": "Ακολούθηση χρήστη;",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Απόκρυψη καρτέλας",
|
||||||
|
"confirmations.hide_featured_tab.intro": "Μπορείτε να το αλλάξετε ανά πάσα στιγμή κάτω από το <i>Επεξεργασία προφίλ> Ρυθμίσεις καρτελών προφίλ</i>.",
|
||||||
|
"confirmations.hide_featured_tab.message": "Αυτό θα κρύψει την καρτέλα για τους χρήστες στο {serverName} και σε άλλους διακομιστές που εκτελούν την τελευταία έκδοση του Mastodon. Άλλες εμφανίσεις μπορεί να ποικίλλουν.",
|
||||||
|
"confirmations.hide_featured_tab.title": "Απόκρυψη καρτέλας \"Αναδεδειγμένα\";",
|
||||||
"confirmations.logout.confirm": "Αποσύνδεση",
|
"confirmations.logout.confirm": "Αποσύνδεση",
|
||||||
"confirmations.logout.message": "Σίγουρα θέλεις να αποσυνδεθείς;",
|
"confirmations.logout.message": "Σίγουρα θέλεις να αποσυνδεθείς;",
|
||||||
"confirmations.logout.title": "Αποσύνδεση;",
|
"confirmations.logout.title": "Αποσύνδεση;",
|
||||||
@ -606,14 +612,13 @@
|
|||||||
"emoji_button.search_results": "Αποτελέσματα αναζήτησης",
|
"emoji_button.search_results": "Αποτελέσματα αναζήτησης",
|
||||||
"emoji_button.symbols": "Σύμβολα",
|
"emoji_button.symbols": "Σύμβολα",
|
||||||
"emoji_button.travel": "Ταξίδια & Τοποθεσίες",
|
"emoji_button.travel": "Ταξίδια & Τοποθεσίες",
|
||||||
"empty_column.account_featured.other": "Ο/Η {acct} δεν έχει αναδείξει τίποτα ακόμη. Γνώριζες ότι μπορείς να αναδείξεις τις ετικέτες που χρησιμοποιείς περισσότερο, ακόμη και τους λογαριασμούς των φίλων σου στο προφίλ σου;",
|
"empty_column.account_featured.other": "Ο/Η {acct} δεν έχει αναδείξει τίποτα ακόμη.",
|
||||||
"empty_column.account_featured_other.no_collections_desc": "Ο χρήστης {acct} δεν έχει δημιουργήσει ακόμη καμία συλλογή.",
|
|
||||||
"empty_column.account_featured_other.title": "Δεν υπάρχει τίποτα να δείτε εδώ",
|
|
||||||
"empty_column.account_featured_self.no_collections": "Καμία συλλογή ακόμη",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Δημιουργήστε μια συλλογή",
|
"empty_column.account_featured_self.no_collections_button": "Δημιουργήστε μια συλλογή",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "Απόκρυψη αυτής της καρτέλας αντ' αυτού",
|
||||||
"empty_column.account_featured_self.pre_collections": "Μείνετε συντονισμένοι για τις Συλλογές",
|
"empty_column.account_featured_self.pre_collections": "Μείνετε συντονισμένοι για τις Συλλογές",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Οι Συλλογές (που έρχονται στο Mastodon 4.6) σας επιτρέπουν να δημιουργήσετε τις δικές σας επιμελημένες λίστες λογαριασμών για να συστήσετε σε άλλους.",
|
"empty_column.account_featured_self.pre_collections_desc": "Οι Συλλογές (που έρχονται στο Mastodon 4.6) επιτρέπουν να δημιουργήσετε τις δικές σας επιμελημένες λίστες λογαριασμών για να συστήσετε σε άλλους.",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Αυτός ο λογαριασμός δεν έχει δημιουργήσει ακόμη καμία συλλογή.",
|
"empty_column.account_featured_self.showcase_accounts": "Παρουσιάστε τους αγαπημένους σας λογαριασμούς",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "Οι συλλογές είναι επιμελημένες λίστες λογαριασμών για να βοηθήσουν άλλους να ανακαλύψουν περισσότερα από το Fediverse.",
|
||||||
"empty_column.account_featured_unknown.other": "Αυτός ο λογαριασμός δεν έχει αναδείξει τίποτα ακόμη.",
|
"empty_column.account_featured_unknown.other": "Αυτός ο λογαριασμός δεν έχει αναδείξει τίποτα ακόμη.",
|
||||||
"empty_column.account_hides_collections": "Αυτός ο χρήστης έχει επιλέξει να μην καταστήσει αυτές τις πληροφορίες διαθέσιμες",
|
"empty_column.account_hides_collections": "Αυτός ο χρήστης έχει επιλέξει να μην καταστήσει αυτές τις πληροφορίες διαθέσιμες",
|
||||||
"empty_column.account_suspended": "Λογαριασμός σε αναστολή",
|
"empty_column.account_suspended": "Λογαριασμός σε αναστολή",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "Featured",
|
"account.featured": "Featured",
|
||||||
"account.featured.accounts": "Profiles",
|
"account.featured.accounts": "Profiles",
|
||||||
"account.featured.collections": "Collections",
|
"account.featured.collections": "Collections",
|
||||||
|
"account.featured.new_collection": "New collection",
|
||||||
"account.field_overflow": "Show full content",
|
"account.field_overflow": "Show full content",
|
||||||
"account.filters.all": "All activity",
|
"account.filters.all": "All activity",
|
||||||
"account.filters.boosts_toggle": "Show boosts",
|
"account.filters.boosts_toggle": "Show boosts",
|
||||||
@ -102,6 +103,7 @@
|
|||||||
"account.muted": "Muted",
|
"account.muted": "Muted",
|
||||||
"account.muting": "Muting",
|
"account.muting": "Muting",
|
||||||
"account.mutual": "You follow each other",
|
"account.mutual": "You follow each other",
|
||||||
|
"account.name.copy": "Copy handle",
|
||||||
"account.name.help.domain": "{domain} is the server that hosts the user’s profile and posts.",
|
"account.name.help.domain": "{domain} is the server that hosts the user’s profile and posts.",
|
||||||
"account.name.help.domain_self": "{domain} is your server that hosts your profile and posts.",
|
"account.name.help.domain_self": "{domain} is your server that hosts your profile and posts.",
|
||||||
"account.name.help.footer": "Just like you can send emails to people using different email clients, you can interact with people on other Mastodon servers – and with anyone on other social apps powered by the same set of rules as Mastodon uses (the ActivityPub protocol).",
|
"account.name.help.footer": "Just like you can send emails to people using different email clients, you can interact with people on other Mastodon servers – and with anyone on other social apps powered by the same set of rules as Mastodon uses (the ActivityPub protocol).",
|
||||||
@ -138,6 +140,9 @@
|
|||||||
"account.unmute": "Unmute @{name}",
|
"account.unmute": "Unmute @{name}",
|
||||||
"account.unmute_notifications_short": "Unmute notifications",
|
"account.unmute_notifications_short": "Unmute notifications",
|
||||||
"account.unmute_short": "Unmute",
|
"account.unmute_short": "Unmute",
|
||||||
|
"account_edit.advanced_settings.bot_hint": "Signal to others that the account mainly performs automated actions and might not be monitored",
|
||||||
|
"account_edit.advanced_settings.bot_label": "Automated account",
|
||||||
|
"account_edit.advanced_settings.title": "Advanced settings",
|
||||||
"account_edit.bio.add_label": "",
|
"account_edit.bio.add_label": "",
|
||||||
"account_edit.bio.edit_label": "Edit bio",
|
"account_edit.bio.edit_label": "Edit bio",
|
||||||
"account_edit.bio.placeholder": "Add a short introduction to help others identify you.",
|
"account_edit.bio.placeholder": "Add a short introduction to help others identify you.",
|
||||||
@ -346,7 +351,7 @@
|
|||||||
"closed_registrations_modal.find_another_server": "Find another server",
|
"closed_registrations_modal.find_another_server": "Find another server",
|
||||||
"closed_registrations_modal.preamble": "Mastodon is decentralised, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!",
|
"closed_registrations_modal.preamble": "Mastodon is decentralised, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!",
|
||||||
"closed_registrations_modal.title": "Signing up on Mastodon",
|
"closed_registrations_modal.title": "Signing up on Mastodon",
|
||||||
"collection.share_modal.share_link_label": "Invite share link",
|
"collection.share_modal.share_link_label": "Share link",
|
||||||
"collection.share_modal.share_via_post": "Post on Mastodon",
|
"collection.share_modal.share_via_post": "Post on Mastodon",
|
||||||
"collection.share_modal.share_via_system": "Share to…",
|
"collection.share_modal.share_via_system": "Share to…",
|
||||||
"collection.share_modal.title": "Share collection",
|
"collection.share_modal.title": "Share collection",
|
||||||
@ -380,6 +385,7 @@
|
|||||||
"collections.detail.sensitive_content": "Sensitive content",
|
"collections.detail.sensitive_content": "Sensitive content",
|
||||||
"collections.detail.sensitive_note": "This collection contains accounts and content that may be sensitive to some users.",
|
"collections.detail.sensitive_note": "This collection contains accounts and content that may be sensitive to some users.",
|
||||||
"collections.detail.share": "Share this collection",
|
"collections.detail.share": "Share this collection",
|
||||||
|
"collections.detail.you_are_in_this_collection": "You're featured in this collection",
|
||||||
"collections.edit_details": "Edit details",
|
"collections.edit_details": "Edit details",
|
||||||
"collections.error_loading_collections": "There was an error when trying to load your collections.",
|
"collections.error_loading_collections": "There was an error when trying to load your collections.",
|
||||||
"collections.hints.accounts_counter": "{count} / {max} accounts",
|
"collections.hints.accounts_counter": "{count} / {max} accounts",
|
||||||
@ -411,7 +417,6 @@
|
|||||||
"column.about": "About",
|
"column.about": "About",
|
||||||
"column.blocks": "Blocked users",
|
"column.blocks": "Blocked users",
|
||||||
"column.bookmarks": "Bookmarks",
|
"column.bookmarks": "Bookmarks",
|
||||||
"column.collections": "My collections",
|
|
||||||
"column.community": "Local timeline",
|
"column.community": "Local timeline",
|
||||||
"column.create_list": "Create list",
|
"column.create_list": "Create list",
|
||||||
"column.direct": "Private mentions",
|
"column.direct": "Private mentions",
|
||||||
@ -427,7 +432,9 @@
|
|||||||
"column.list_members": "Manage list members",
|
"column.list_members": "Manage list members",
|
||||||
"column.lists": "Lists",
|
"column.lists": "Lists",
|
||||||
"column.mutes": "Muted users",
|
"column.mutes": "Muted users",
|
||||||
|
"column.my_collections": "My collections",
|
||||||
"column.notifications": "Notifications",
|
"column.notifications": "Notifications",
|
||||||
|
"column.other_collections": "Collections by {name}",
|
||||||
"column.pins": "Pinned posts",
|
"column.pins": "Pinned posts",
|
||||||
"column.public": "Federated timeline",
|
"column.public": "Federated timeline",
|
||||||
"column_back_button.label": "Back",
|
"column_back_button.label": "Back",
|
||||||
@ -497,6 +504,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Follow and add to list",
|
"confirmations.follow_to_list.confirm": "Follow and add to list",
|
||||||
"confirmations.follow_to_list.message": "You need to be following {name} to add them to a list.",
|
"confirmations.follow_to_list.message": "You need to be following {name} to add them to a list.",
|
||||||
"confirmations.follow_to_list.title": "Follow user?",
|
"confirmations.follow_to_list.title": "Follow user?",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Hide tab",
|
||||||
|
"confirmations.hide_featured_tab.intro": "You can change this at any time under <i>Edit profile > Profile tab settings</i>.",
|
||||||
|
"confirmations.hide_featured_tab.message": "This will hide the tab for users on {serverName} and other servers running the latest version of Mastodon. Other displays may vary.",
|
||||||
|
"confirmations.hide_featured_tab.title": "Hide \"Featured\" tab?",
|
||||||
"confirmations.logout.confirm": "Log out",
|
"confirmations.logout.confirm": "Log out",
|
||||||
"confirmations.logout.message": "Are you sure you want to log out?",
|
"confirmations.logout.message": "Are you sure you want to log out?",
|
||||||
"confirmations.logout.title": "Log out?",
|
"confirmations.logout.title": "Log out?",
|
||||||
@ -535,6 +546,7 @@
|
|||||||
"content_warning.hide": "Hide post",
|
"content_warning.hide": "Hide post",
|
||||||
"content_warning.show": "Show anyway",
|
"content_warning.show": "Show anyway",
|
||||||
"content_warning.show_more": "Show more",
|
"content_warning.show_more": "Show more",
|
||||||
|
"content_warning.show_short": "Show",
|
||||||
"conversation.delete": "Delete conversation",
|
"conversation.delete": "Delete conversation",
|
||||||
"conversation.mark_as_read": "Mark as read",
|
"conversation.mark_as_read": "Mark as read",
|
||||||
"conversation.open": "View conversation",
|
"conversation.open": "View conversation",
|
||||||
@ -575,6 +587,14 @@
|
|||||||
"domain_pill.your_server": "Your digital home, where all of your posts live. Don’t like this one? Transfer servers at any time and bring your followers too.",
|
"domain_pill.your_server": "Your digital home, where all of your posts live. Don’t like this one? Transfer servers at any time and bring your followers too.",
|
||||||
"domain_pill.your_username": "Your unique identifier on this server. It’s possible to find users with the same username on different servers.",
|
"domain_pill.your_username": "Your unique identifier on this server. It’s possible to find users with the same username on different servers.",
|
||||||
"dropdown.empty": "Select an option",
|
"dropdown.empty": "Select an option",
|
||||||
|
"email_subscriptions.email": "Email",
|
||||||
|
"email_subscriptions.form.action": "Subscribe",
|
||||||
|
"email_subscriptions.form.bottom": "Get posts in your inbox without creating a Mastodon account. Unsubscribe at any time. For more information, refer to the <a>Privacy Policy</a>.",
|
||||||
|
"email_subscriptions.form.title": "Sign up for email updates from {name}",
|
||||||
|
"email_subscriptions.submitted.lead": "Check your inbox for an email to finish signing up for email updates.",
|
||||||
|
"email_subscriptions.submitted.title": "One more step",
|
||||||
|
"email_subscriptions.validation.email.blocked": "Blocked email provider",
|
||||||
|
"email_subscriptions.validation.email.invalid": "Invalid email address",
|
||||||
"embed.instructions": "Embed this post on your website by copying the code below.",
|
"embed.instructions": "Embed this post on your website by copying the code below.",
|
||||||
"embed.preview": "Here is what it will look like:",
|
"embed.preview": "Here is what it will look like:",
|
||||||
"emoji_button.activity": "Activity",
|
"emoji_button.activity": "Activity",
|
||||||
@ -592,7 +612,14 @@
|
|||||||
"emoji_button.search_results": "Search results",
|
"emoji_button.search_results": "Search results",
|
||||||
"emoji_button.symbols": "Symbols",
|
"emoji_button.symbols": "Symbols",
|
||||||
"emoji_button.travel": "Travel & Places",
|
"emoji_button.travel": "Travel & Places",
|
||||||
"empty_column.account_featured.other": "{acct} has not featured anything yet. Did you know that you can feature your hashtags you use the most, and even your friend’s accounts on your profile?",
|
"empty_column.account_featured.other": "{acct} has not featured anything yet.",
|
||||||
|
"empty_column.account_featured_self.no_collections_button": "Create a collection",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "Hide this tab instead",
|
||||||
|
"empty_column.account_featured_self.pre_collections": "Stay tuned for Collections",
|
||||||
|
"empty_column.account_featured_self.pre_collections_desc": "Collections (coming in Mastodon 4.6) allow you to create your own curated lists of accounts to recommend to others.",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts": "Showcase your favourite accounts",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "Collections are curated lists of accounts to help others discover more of the Fediverse.",
|
||||||
|
"empty_column.account_featured_unknown.other": "This account hasn’t featured anything yet.",
|
||||||
"empty_column.account_hides_collections": "This user has chosen not to make this information available",
|
"empty_column.account_hides_collections": "This user has chosen not to make this information available",
|
||||||
"empty_column.account_suspended": "Account suspended",
|
"empty_column.account_suspended": "Account suspended",
|
||||||
"empty_column.account_timeline": "No posts here!",
|
"empty_column.account_timeline": "No posts here!",
|
||||||
@ -632,6 +659,10 @@
|
|||||||
"featured_carousel.header": "{count, plural, one {Pinned Post} other {Pinned Posts}}",
|
"featured_carousel.header": "{count, plural, one {Pinned Post} other {Pinned Posts}}",
|
||||||
"featured_carousel.slide": "Post {current, number} of {max, number}",
|
"featured_carousel.slide": "Post {current, number} of {max, number}",
|
||||||
"featured_tags.more_items": "+{count}",
|
"featured_tags.more_items": "+{count}",
|
||||||
|
"featured_tags.suggestions": "Lately you’ve posted about {items}. Add these as featured hashtags?",
|
||||||
|
"featured_tags.suggestions.add": "Add",
|
||||||
|
"featured_tags.suggestions.added": "Manage your featured hashtags at any time under <link>Edit Profile > Featured hashtags</link>.",
|
||||||
|
"featured_tags.suggestions.dismiss": "No thanks",
|
||||||
"filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
|
"filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
|
||||||
"filter_modal.added.context_mismatch_title": "Context mismatch!",
|
"filter_modal.added.context_mismatch_title": "Context mismatch!",
|
||||||
"filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
|
"filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
|
||||||
@ -674,7 +705,9 @@
|
|||||||
"follow_suggestions.who_to_follow": "Who to follow",
|
"follow_suggestions.who_to_follow": "Who to follow",
|
||||||
"followed_tags": "Followed hashtags",
|
"followed_tags": "Followed hashtags",
|
||||||
"followers.hide_other_followers": "This user has chosen not to make their other followers visible",
|
"followers.hide_other_followers": "This user has chosen not to make their other followers visible",
|
||||||
|
"followers.title": "Following {name}",
|
||||||
"following.hide_other_following": "This user has chosen not to make the rest of who they follow visible",
|
"following.hide_other_following": "This user has chosen not to make the rest of who they follow visible",
|
||||||
|
"following.title": "Followed by {name}",
|
||||||
"footer.about": "About",
|
"footer.about": "About",
|
||||||
"footer.about_mastodon": "About Mastodon",
|
"footer.about_mastodon": "About Mastodon",
|
||||||
"footer.about_server": "About {domain}",
|
"footer.about_server": "About {domain}",
|
||||||
@ -686,6 +719,7 @@
|
|||||||
"footer.source_code": "View source code",
|
"footer.source_code": "View source code",
|
||||||
"footer.status": "Status",
|
"footer.status": "Status",
|
||||||
"footer.terms_of_service": "Terms of service",
|
"footer.terms_of_service": "Terms of service",
|
||||||
|
"form_error.blank": "Field cannot be blank.",
|
||||||
"form_field.optional": "(optional)",
|
"form_field.optional": "(optional)",
|
||||||
"generic.saved": "Saved",
|
"generic.saved": "Saved",
|
||||||
"getting_started.heading": "Getting started",
|
"getting_started.heading": "Getting started",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "Featured",
|
"account.featured": "Featured",
|
||||||
"account.featured.accounts": "Profiles",
|
"account.featured.accounts": "Profiles",
|
||||||
"account.featured.collections": "Collections",
|
"account.featured.collections": "Collections",
|
||||||
|
"account.featured.new_collection": "New collection",
|
||||||
"account.field_overflow": "Show full content",
|
"account.field_overflow": "Show full content",
|
||||||
"account.filters.all": "All activity",
|
"account.filters.all": "All activity",
|
||||||
"account.filters.boosts_toggle": "Show boosts",
|
"account.filters.boosts_toggle": "Show boosts",
|
||||||
@ -350,7 +351,7 @@
|
|||||||
"closed_registrations_modal.find_another_server": "Find another server",
|
"closed_registrations_modal.find_another_server": "Find another server",
|
||||||
"closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!",
|
"closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!",
|
||||||
"closed_registrations_modal.title": "Signing up on Mastodon",
|
"closed_registrations_modal.title": "Signing up on Mastodon",
|
||||||
"collection.share_modal.share_link_label": "Invite share link",
|
"collection.share_modal.share_link_label": "Share link",
|
||||||
"collection.share_modal.share_via_post": "Post on Mastodon",
|
"collection.share_modal.share_via_post": "Post on Mastodon",
|
||||||
"collection.share_modal.share_via_system": "Share to…",
|
"collection.share_modal.share_via_system": "Share to…",
|
||||||
"collection.share_modal.title": "Share collection",
|
"collection.share_modal.title": "Share collection",
|
||||||
@ -416,7 +417,6 @@
|
|||||||
"column.about": "About",
|
"column.about": "About",
|
||||||
"column.blocks": "Blocked users",
|
"column.blocks": "Blocked users",
|
||||||
"column.bookmarks": "Bookmarks",
|
"column.bookmarks": "Bookmarks",
|
||||||
"column.collections": "My collections",
|
|
||||||
"column.community": "Local timeline",
|
"column.community": "Local timeline",
|
||||||
"column.create_list": "Create list",
|
"column.create_list": "Create list",
|
||||||
"column.direct": "Private mentions",
|
"column.direct": "Private mentions",
|
||||||
@ -432,7 +432,9 @@
|
|||||||
"column.list_members": "Manage list members",
|
"column.list_members": "Manage list members",
|
||||||
"column.lists": "Lists",
|
"column.lists": "Lists",
|
||||||
"column.mutes": "Muted users",
|
"column.mutes": "Muted users",
|
||||||
|
"column.my_collections": "My collections",
|
||||||
"column.notifications": "Notifications",
|
"column.notifications": "Notifications",
|
||||||
|
"column.other_collections": "Collections by {name}",
|
||||||
"column.pins": "Pinned posts",
|
"column.pins": "Pinned posts",
|
||||||
"column.public": "Federated timeline",
|
"column.public": "Federated timeline",
|
||||||
"column_back_button.label": "Back",
|
"column_back_button.label": "Back",
|
||||||
@ -502,6 +504,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Follow and add to list",
|
"confirmations.follow_to_list.confirm": "Follow and add to list",
|
||||||
"confirmations.follow_to_list.message": "You need to be following {name} to add them to a list.",
|
"confirmations.follow_to_list.message": "You need to be following {name} to add them to a list.",
|
||||||
"confirmations.follow_to_list.title": "Follow user?",
|
"confirmations.follow_to_list.title": "Follow user?",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Hide tab",
|
||||||
|
"confirmations.hide_featured_tab.intro": "You can change this at any time under <i>Edit profile > Profile tab settings</i>.",
|
||||||
|
"confirmations.hide_featured_tab.message": "This will hide the tab for users on {serverName} and other servers running the latest version of Mastodon. Other displays may vary.",
|
||||||
|
"confirmations.hide_featured_tab.title": "Hide \"Featured\" tab?",
|
||||||
"confirmations.logout.confirm": "Log out",
|
"confirmations.logout.confirm": "Log out",
|
||||||
"confirmations.logout.message": "Are you sure you want to log out?",
|
"confirmations.logout.message": "Are you sure you want to log out?",
|
||||||
"confirmations.logout.title": "Log out?",
|
"confirmations.logout.title": "Log out?",
|
||||||
@ -606,14 +612,13 @@
|
|||||||
"emoji_button.search_results": "Search results",
|
"emoji_button.search_results": "Search results",
|
||||||
"emoji_button.symbols": "Symbols",
|
"emoji_button.symbols": "Symbols",
|
||||||
"emoji_button.travel": "Travel & Places",
|
"emoji_button.travel": "Travel & Places",
|
||||||
"empty_column.account_featured.other": "{acct} has not featured anything yet. Did you know that you can feature your hashtags you use the most, and even your friend’s accounts on your profile?",
|
"empty_column.account_featured.other": "{acct} has not featured anything yet.",
|
||||||
"empty_column.account_featured_other.no_collections_desc": "{acct} hasn’t created any collections yet.",
|
|
||||||
"empty_column.account_featured_other.title": "Nothing to see here",
|
|
||||||
"empty_column.account_featured_self.no_collections": "No collections yet",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Create a collection",
|
"empty_column.account_featured_self.no_collections_button": "Create a collection",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "Hide this tab instead",
|
||||||
"empty_column.account_featured_self.pre_collections": "Stay tuned for Collections",
|
"empty_column.account_featured_self.pre_collections": "Stay tuned for Collections",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Collections (coming in Mastodon 4.6) allows you to create your own curated lists of accounts to recommend to others.",
|
"empty_column.account_featured_self.pre_collections_desc": "Collections (coming in Mastodon 4.6) allow you to create your own curated lists of accounts to recommend to others.",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "This account hasn’t created any collections yet.",
|
"empty_column.account_featured_self.showcase_accounts": "Showcase your favorite accounts",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "Collections are curated lists of accounts to help others discover more of the Fediverse.",
|
||||||
"empty_column.account_featured_unknown.other": "This account hasn’t featured anything yet.",
|
"empty_column.account_featured_unknown.other": "This account hasn’t featured anything yet.",
|
||||||
"empty_column.account_hides_collections": "This user has chosen to not make this information available",
|
"empty_column.account_hides_collections": "This user has chosen to not make this information available",
|
||||||
"empty_column.account_suspended": "Account suspended",
|
"empty_column.account_suspended": "Account suspended",
|
||||||
@ -898,6 +903,7 @@
|
|||||||
"navigation_panel.expand_followed_tags": "Expand followed hashtags menu",
|
"navigation_panel.expand_followed_tags": "Expand followed hashtags menu",
|
||||||
"navigation_panel.expand_lists": "Expand list menu",
|
"navigation_panel.expand_lists": "Expand list menu",
|
||||||
"not_signed_in_indicator.not_signed_in": "You need to login to access this resource.",
|
"not_signed_in_indicator.not_signed_in": "You need to login to access this resource.",
|
||||||
|
"notification.added_to_collection": "{name} added you to a collection",
|
||||||
"notification.admin.report": "{name} reported {target}",
|
"notification.admin.report": "{name} reported {target}",
|
||||||
"notification.admin.report_account": "{name} reported {count, plural, one {one post} other {# posts}} from {target} for {category}",
|
"notification.admin.report_account": "{name} reported {count, plural, one {one post} other {# posts}} from {target} for {category}",
|
||||||
"notification.admin.report_account_other": "{name} reported {count, plural, one {one post} other {# posts}} from {target}",
|
"notification.admin.report_account_other": "{name} reported {count, plural, one {one post} other {# posts}} from {target}",
|
||||||
@ -907,6 +913,7 @@
|
|||||||
"notification.admin.sign_up.name_and_others": "{name} and {count, plural, one {# other} other {# others}} signed up",
|
"notification.admin.sign_up.name_and_others": "{name} and {count, plural, one {# other} other {# others}} signed up",
|
||||||
"notification.annual_report.message": "Your {year} #Wrapstodon awaits! Unveil your year's highlights and memorable moments on Mastodon!",
|
"notification.annual_report.message": "Your {year} #Wrapstodon awaits! Unveil your year's highlights and memorable moments on Mastodon!",
|
||||||
"notification.annual_report.view": "View #Wrapstodon",
|
"notification.annual_report.view": "View #Wrapstodon",
|
||||||
|
"notification.collection_update": "{name} edited a collection you’re in",
|
||||||
"notification.favourite": "{name} favorited your post",
|
"notification.favourite": "{name} favorited your post",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} and <a>{count, plural, one {# other} other {# others}}</a> favorited your post",
|
"notification.favourite.name_and_others_with_link": "{name} and <a>{count, plural, one {# other} other {# others}}</a> favorited your post",
|
||||||
"notification.favourite_pm": "{name} favorited your private mention",
|
"notification.favourite_pm": "{name} favorited your private mention",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "Destacados",
|
"account.featured": "Destacados",
|
||||||
"account.featured.accounts": "Perfiles",
|
"account.featured.accounts": "Perfiles",
|
||||||
"account.featured.collections": "Colecciones",
|
"account.featured.collections": "Colecciones",
|
||||||
|
"account.featured.new_collection": "Nueva colección",
|
||||||
"account.field_overflow": "Mostrar contenido completo",
|
"account.field_overflow": "Mostrar contenido completo",
|
||||||
"account.filters.all": "Toda la actividad",
|
"account.filters.all": "Toda la actividad",
|
||||||
"account.filters.boosts_toggle": "Mostrar adhesiones",
|
"account.filters.boosts_toggle": "Mostrar adhesiones",
|
||||||
@ -416,7 +417,6 @@
|
|||||||
"column.about": "Información",
|
"column.about": "Información",
|
||||||
"column.blocks": "Usuarios bloqueados",
|
"column.blocks": "Usuarios bloqueados",
|
||||||
"column.bookmarks": "Marcadores",
|
"column.bookmarks": "Marcadores",
|
||||||
"column.collections": "Mis colecciones",
|
|
||||||
"column.community": "Línea temporal local",
|
"column.community": "Línea temporal local",
|
||||||
"column.create_list": "Crear lista",
|
"column.create_list": "Crear lista",
|
||||||
"column.direct": "Menciones privadas",
|
"column.direct": "Menciones privadas",
|
||||||
@ -432,7 +432,9 @@
|
|||||||
"column.list_members": "Administrar miembros de la lista",
|
"column.list_members": "Administrar miembros de la lista",
|
||||||
"column.lists": "Listas",
|
"column.lists": "Listas",
|
||||||
"column.mutes": "Usuarios silenciados",
|
"column.mutes": "Usuarios silenciados",
|
||||||
|
"column.my_collections": "Mis colecciones",
|
||||||
"column.notifications": "Notificaciones",
|
"column.notifications": "Notificaciones",
|
||||||
|
"column.other_collections": "Colecciones de {name}",
|
||||||
"column.pins": "Mensajes fijados",
|
"column.pins": "Mensajes fijados",
|
||||||
"column.public": "Línea temporal federada",
|
"column.public": "Línea temporal federada",
|
||||||
"column_back_button.label": "Volver",
|
"column_back_button.label": "Volver",
|
||||||
@ -502,6 +504,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Seguir y agregar a la lista",
|
"confirmations.follow_to_list.confirm": "Seguir y agregar a la lista",
|
||||||
"confirmations.follow_to_list.message": "Necesitás seguir a {name} para agregarle a una lista.",
|
"confirmations.follow_to_list.message": "Necesitás seguir a {name} para agregarle a una lista.",
|
||||||
"confirmations.follow_to_list.title": "¿Querés seguirle?",
|
"confirmations.follow_to_list.title": "¿Querés seguirle?",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Ocultar pestaña",
|
||||||
|
"confirmations.hide_featured_tab.intro": "Podés cambiar esto en cualquier momento en <i>Editar perfil > Configuración de pestaña de perfil</i>.",
|
||||||
|
"confirmations.hide_featured_tab.message": "Esto ocultará la pestaña para los usuarios en {serverName} y otros servidores que tengan instalada la última versión de Mastodon. Otras pantallas pueden variar.",
|
||||||
|
"confirmations.hide_featured_tab.title": "¿Ocultar la pestaña «Destacados»?",
|
||||||
"confirmations.logout.confirm": "Cerrar sesión",
|
"confirmations.logout.confirm": "Cerrar sesión",
|
||||||
"confirmations.logout.message": "¿De verdad querés cerrar la sesión?",
|
"confirmations.logout.message": "¿De verdad querés cerrar la sesión?",
|
||||||
"confirmations.logout.title": "¿Cerrar sesión?",
|
"confirmations.logout.title": "¿Cerrar sesión?",
|
||||||
@ -606,14 +612,13 @@
|
|||||||
"emoji_button.search_results": "Resultados de búsqueda",
|
"emoji_button.search_results": "Resultados de búsqueda",
|
||||||
"emoji_button.symbols": "Símbolos",
|
"emoji_button.symbols": "Símbolos",
|
||||||
"emoji_button.travel": "Viajes y lugares",
|
"emoji_button.travel": "Viajes y lugares",
|
||||||
"empty_column.account_featured.other": "{acct} todavía no destacó nada. ¿Sabías que en tu perfil podés destacar tus etiquetas que más usás e incluso las cuentas de tus contactos?",
|
"empty_column.account_featured.other": "{acct} todavía no destacó nada.",
|
||||||
"empty_column.account_featured_other.no_collections_desc": "{acct} todavía no creó ninguna colección.",
|
|
||||||
"empty_column.account_featured_other.title": "No hay nada por acá",
|
|
||||||
"empty_column.account_featured_self.no_collections": "No hay colecciones aún",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Crear colección",
|
"empty_column.account_featured_self.no_collections_button": "Crear colección",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "En su lugar, ocultar esta pestaña",
|
||||||
"empty_column.account_featured_self.pre_collections": "Mantenete pendiente de las colecciones",
|
"empty_column.account_featured_self.pre_collections": "Mantenete pendiente de las colecciones",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Las colecciones (que vendrán en Mastodon 4.6) te permite crear tus propias listas de cuentas seleccionadas para recomendar a otras personas.",
|
"empty_column.account_featured_self.pre_collections_desc": "Las colecciones (que vendrán en Mastodon 4.6) te permiten crear tus propias listas de cuentas seleccionadas para recomendar a otras personas.",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Esta cuenta todavía no creó ninguna colección.",
|
"empty_column.account_featured_self.showcase_accounts": "Mostrá tus cuentas favoritas",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "Las colecciones son listas de cuentas seleccionadas para ayudar a otras personas a descubrir más del Fediverso.",
|
||||||
"empty_column.account_featured_unknown.other": "Esta cuenta todavía no destacó nada.",
|
"empty_column.account_featured_unknown.other": "Esta cuenta todavía no destacó nada.",
|
||||||
"empty_column.account_hides_collections": "Este usuario eligió no publicar esta información",
|
"empty_column.account_hides_collections": "Este usuario eligió no publicar esta información",
|
||||||
"empty_column.account_suspended": "Cuenta suspendida",
|
"empty_column.account_suspended": "Cuenta suspendida",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "Destacado",
|
"account.featured": "Destacado",
|
||||||
"account.featured.accounts": "Perfiles",
|
"account.featured.accounts": "Perfiles",
|
||||||
"account.featured.collections": "Colecciones",
|
"account.featured.collections": "Colecciones",
|
||||||
|
"account.featured.new_collection": "Nueva colección",
|
||||||
"account.field_overflow": "Mostrar contenido completo",
|
"account.field_overflow": "Mostrar contenido completo",
|
||||||
"account.filters.all": "Toda la actividad",
|
"account.filters.all": "Toda la actividad",
|
||||||
"account.filters.boosts_toggle": "Mostrar impulsos",
|
"account.filters.boosts_toggle": "Mostrar impulsos",
|
||||||
@ -416,7 +417,6 @@
|
|||||||
"column.about": "Acerca de",
|
"column.about": "Acerca de",
|
||||||
"column.blocks": "Usuarios bloqueados",
|
"column.blocks": "Usuarios bloqueados",
|
||||||
"column.bookmarks": "Marcadores",
|
"column.bookmarks": "Marcadores",
|
||||||
"column.collections": "Mis colecciones",
|
|
||||||
"column.community": "Cronología local",
|
"column.community": "Cronología local",
|
||||||
"column.create_list": "Crear lista",
|
"column.create_list": "Crear lista",
|
||||||
"column.direct": "Menciones privadas",
|
"column.direct": "Menciones privadas",
|
||||||
@ -432,7 +432,9 @@
|
|||||||
"column.list_members": "Administrar miembros de la lista",
|
"column.list_members": "Administrar miembros de la lista",
|
||||||
"column.lists": "Listas",
|
"column.lists": "Listas",
|
||||||
"column.mutes": "Usuarios silenciados",
|
"column.mutes": "Usuarios silenciados",
|
||||||
|
"column.my_collections": "Mis colecciones",
|
||||||
"column.notifications": "Notificaciones",
|
"column.notifications": "Notificaciones",
|
||||||
|
"column.other_collections": "Colecciones de {name}",
|
||||||
"column.pins": "Publicaciones fijadas",
|
"column.pins": "Publicaciones fijadas",
|
||||||
"column.public": "Cronología federada",
|
"column.public": "Cronología federada",
|
||||||
"column_back_button.label": "Atrás",
|
"column_back_button.label": "Atrás",
|
||||||
@ -502,6 +504,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Seguir y agregar a la lista",
|
"confirmations.follow_to_list.confirm": "Seguir y agregar a la lista",
|
||||||
"confirmations.follow_to_list.message": "Tienes que seguir a {name} para añadirlo a una lista.",
|
"confirmations.follow_to_list.message": "Tienes que seguir a {name} para añadirlo a una lista.",
|
||||||
"confirmations.follow_to_list.title": "¿Seguir a usuario?",
|
"confirmations.follow_to_list.title": "¿Seguir a usuario?",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Ocultar pestaña",
|
||||||
|
"confirmations.hide_featured_tab.intro": "Puedes cambiar esto en cualquier momento en <i>Editar perfil > Configuración de la pestaña Perfil</i>.",
|
||||||
|
"confirmations.hide_featured_tab.message": "Esto ocultará la pestaña para los usuarios de {serverName} y otros servidores que ejecuten la última versión de Mastodon. La visualización puede variar en otros casos.",
|
||||||
|
"confirmations.hide_featured_tab.title": "¿Deseas ocultar la pestaña \"Destacado\"?",
|
||||||
"confirmations.logout.confirm": "Cerrar sesión",
|
"confirmations.logout.confirm": "Cerrar sesión",
|
||||||
"confirmations.logout.message": "¿Estás seguro de que quieres cerrar la sesión?",
|
"confirmations.logout.message": "¿Estás seguro de que quieres cerrar la sesión?",
|
||||||
"confirmations.logout.title": "¿Deseas cerrar sesión?",
|
"confirmations.logout.title": "¿Deseas cerrar sesión?",
|
||||||
@ -606,14 +612,13 @@
|
|||||||
"emoji_button.search_results": "Resultados de búsqueda",
|
"emoji_button.search_results": "Resultados de búsqueda",
|
||||||
"emoji_button.symbols": "Símbolos",
|
"emoji_button.symbols": "Símbolos",
|
||||||
"emoji_button.travel": "Viajes y lugares",
|
"emoji_button.travel": "Viajes y lugares",
|
||||||
"empty_column.account_featured.other": "{acct} no ha destacado nada todavía. ¿Sabías que puedes destacar las etiquetas que más usas e incluso las cuentas de tus amigos en tu perfil?",
|
"empty_column.account_featured.other": "{acct} no ha destacado nada todavía.",
|
||||||
"empty_column.account_featured_other.no_collections_desc": "{acct} aún no ha creado ninguna colección.",
|
|
||||||
"empty_column.account_featured_other.title": "Aquí no hay nada que ver",
|
|
||||||
"empty_column.account_featured_self.no_collections": "Aún no hay colecciones",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Crear una colección",
|
"empty_column.account_featured_self.no_collections_button": "Crear una colección",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "Ocultar esta pestaña",
|
||||||
"empty_column.account_featured_self.pre_collections": "No te pierdas las colecciones",
|
"empty_column.account_featured_self.pre_collections": "No te pierdas las colecciones",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Las colecciones (disponibles en Mastodon 4.6) te permiten crear tus propias listas seleccionadas de cuentas para recomendarlas a otras personas.",
|
"empty_column.account_featured_self.pre_collections_desc": "Las colecciones (que llegarán en Mastodon 4.6) te permiten crear tus propias listas de cuentas seleccionadas para recomendarlas a otras personas.",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Esta cuenta aún no ha creado ninguna colección.",
|
"empty_column.account_featured_self.showcase_accounts": "Destaca tus cuentas favoritas",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "Las colecciones son listas de cuentas seleccionadas que ayudan a otros a descubrir más del Fediverso.",
|
||||||
"empty_column.account_featured_unknown.other": "Esta cuenta no ha destacado nada todavía.",
|
"empty_column.account_featured_unknown.other": "Esta cuenta no ha destacado nada todavía.",
|
||||||
"empty_column.account_hides_collections": "Este usuario ha elegido no hacer disponible esta información",
|
"empty_column.account_hides_collections": "Este usuario ha elegido no hacer disponible esta información",
|
||||||
"empty_column.account_suspended": "Cuenta suspendida",
|
"empty_column.account_suspended": "Cuenta suspendida",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "Destacado",
|
"account.featured": "Destacado",
|
||||||
"account.featured.accounts": "Perfiles",
|
"account.featured.accounts": "Perfiles",
|
||||||
"account.featured.collections": "Colecciones",
|
"account.featured.collections": "Colecciones",
|
||||||
|
"account.featured.new_collection": "Nueva colección",
|
||||||
"account.field_overflow": "Mostrar contenido completo",
|
"account.field_overflow": "Mostrar contenido completo",
|
||||||
"account.filters.all": "Toda la actividad",
|
"account.filters.all": "Toda la actividad",
|
||||||
"account.filters.boosts_toggle": "Mostrar impulsos",
|
"account.filters.boosts_toggle": "Mostrar impulsos",
|
||||||
@ -416,7 +417,6 @@
|
|||||||
"column.about": "Acerca de",
|
"column.about": "Acerca de",
|
||||||
"column.blocks": "Usuarios bloqueados",
|
"column.blocks": "Usuarios bloqueados",
|
||||||
"column.bookmarks": "Marcadores",
|
"column.bookmarks": "Marcadores",
|
||||||
"column.collections": "Mis colecciones",
|
|
||||||
"column.community": "Cronología local",
|
"column.community": "Cronología local",
|
||||||
"column.create_list": "Crear lista",
|
"column.create_list": "Crear lista",
|
||||||
"column.direct": "Menciones privadas",
|
"column.direct": "Menciones privadas",
|
||||||
@ -432,7 +432,9 @@
|
|||||||
"column.list_members": "Administrar miembros de la lista",
|
"column.list_members": "Administrar miembros de la lista",
|
||||||
"column.lists": "Listas",
|
"column.lists": "Listas",
|
||||||
"column.mutes": "Usuarios silenciados",
|
"column.mutes": "Usuarios silenciados",
|
||||||
|
"column.my_collections": "Mis colecciones",
|
||||||
"column.notifications": "Notificaciones",
|
"column.notifications": "Notificaciones",
|
||||||
|
"column.other_collections": "Colecciones de {name}",
|
||||||
"column.pins": "Publicaciones fijadas",
|
"column.pins": "Publicaciones fijadas",
|
||||||
"column.public": "Cronología federada",
|
"column.public": "Cronología federada",
|
||||||
"column_back_button.label": "Atrás",
|
"column_back_button.label": "Atrás",
|
||||||
@ -502,6 +504,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Seguir y añadir a la lista",
|
"confirmations.follow_to_list.confirm": "Seguir y añadir a la lista",
|
||||||
"confirmations.follow_to_list.message": "Necesitas seguir a {name} para agregarlo a una lista.",
|
"confirmations.follow_to_list.message": "Necesitas seguir a {name} para agregarlo a una lista.",
|
||||||
"confirmations.follow_to_list.title": "¿Seguir usuario?",
|
"confirmations.follow_to_list.title": "¿Seguir usuario?",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Ocultar pestaña",
|
||||||
|
"confirmations.hide_featured_tab.intro": "Puedes cambiar esto en cualquier momento en <i>Editar perfil > Configuración de pestañas del perfil</i>.",
|
||||||
|
"confirmations.hide_featured_tab.message": "Esto esconderá la pestaña a los usuarios en {serverName} y otros servidores con la última versión de Mastodon. En otros lugares, puede variar.",
|
||||||
|
"confirmations.hide_featured_tab.title": "¿Ocultar la pestaña \"Destacado\"?",
|
||||||
"confirmations.logout.confirm": "Cerrar sesión",
|
"confirmations.logout.confirm": "Cerrar sesión",
|
||||||
"confirmations.logout.message": "¿Seguro que quieres cerrar la sesión?",
|
"confirmations.logout.message": "¿Seguro que quieres cerrar la sesión?",
|
||||||
"confirmations.logout.title": "¿Cerrar sesión?",
|
"confirmations.logout.title": "¿Cerrar sesión?",
|
||||||
@ -606,14 +612,13 @@
|
|||||||
"emoji_button.search_results": "Resultados de búsqueda",
|
"emoji_button.search_results": "Resultados de búsqueda",
|
||||||
"emoji_button.symbols": "Símbolos",
|
"emoji_button.symbols": "Símbolos",
|
||||||
"emoji_button.travel": "Viajes y lugares",
|
"emoji_button.travel": "Viajes y lugares",
|
||||||
"empty_column.account_featured.other": "{acct} aún no ha destacado nada. ¿Sabías que puedes destacar las etiquetas que más usas e incluso las cuentas de tus amigos en tu perfil?",
|
"empty_column.account_featured.other": "{acct} aún no ha destacado nada.",
|
||||||
"empty_column.account_featured_other.no_collections_desc": "{acct} aún no ha creado ninguna colección.",
|
|
||||||
"empty_column.account_featured_other.title": "Nada que ver aquí",
|
|
||||||
"empty_column.account_featured_self.no_collections": "Aún no hay colecciones",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Crear una colección",
|
"empty_column.account_featured_self.no_collections_button": "Crear una colección",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "Ocultar esta pestaña",
|
||||||
"empty_column.account_featured_self.pre_collections": "No te pierdas las Colecciones",
|
"empty_column.account_featured_self.pre_collections": "No te pierdas las Colecciones",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Las colecciones (disponibles en Mastodon 4.6) te permiten crear tus propias listas seleccionadas de cuentas para recomendarlas a otras personas.",
|
"empty_column.account_featured_self.pre_collections_desc": "Las colecciones (disponibles a partir de Mastodon 4.6) te permiten crear tus propias listas de cuentas seleccionadas para recomendarlas a otros.",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Esta cuenta aún no ha creado ninguna colección.",
|
"empty_column.account_featured_self.showcase_accounts": "Muestra tus cuentas favoritas",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "Las colecciones son listas de cuentas seleccionadas para ayudar a otros a descubrir más del Fediverso.",
|
||||||
"empty_column.account_featured_unknown.other": "Esta cuenta no ha destacado nada todavía.",
|
"empty_column.account_featured_unknown.other": "Esta cuenta no ha destacado nada todavía.",
|
||||||
"empty_column.account_hides_collections": "Este usuario ha decidido no mostrar esta información",
|
"empty_column.account_hides_collections": "Este usuario ha decidido no mostrar esta información",
|
||||||
"empty_column.account_suspended": "Cuenta suspendida",
|
"empty_column.account_suspended": "Cuenta suspendida",
|
||||||
|
|||||||
@ -386,7 +386,6 @@
|
|||||||
"column.about": "Teave",
|
"column.about": "Teave",
|
||||||
"column.blocks": "Blokeeritud kasutajad",
|
"column.blocks": "Blokeeritud kasutajad",
|
||||||
"column.bookmarks": "Järjehoidjad",
|
"column.bookmarks": "Järjehoidjad",
|
||||||
"column.collections": "Minu kogumikud",
|
|
||||||
"column.community": "Kohalik ajajoon",
|
"column.community": "Kohalik ajajoon",
|
||||||
"column.create_list": "Loo loend",
|
"column.create_list": "Loo loend",
|
||||||
"column.direct": "Privaatsed mainimised",
|
"column.direct": "Privaatsed mainimised",
|
||||||
@ -560,7 +559,6 @@
|
|||||||
"emoji_button.search_results": "Otsitulemused",
|
"emoji_button.search_results": "Otsitulemused",
|
||||||
"emoji_button.symbols": "Sümbolid",
|
"emoji_button.symbols": "Sümbolid",
|
||||||
"emoji_button.travel": "Reisimine & kohad",
|
"emoji_button.travel": "Reisimine & kohad",
|
||||||
"empty_column.account_featured.other": "{acct} pole veel midagi esile tõstnud. Kas teadsid, et oma profiilis saad esile tõsta rohkem kasutatud teemaviiteid või sõbra kasutajakontot?",
|
|
||||||
"empty_column.account_hides_collections": "See kasutaja otsustas mitte teha seda infot saadavaks",
|
"empty_column.account_hides_collections": "See kasutaja otsustas mitte teha seda infot saadavaks",
|
||||||
"empty_column.account_suspended": "Konto kustutatud",
|
"empty_column.account_suspended": "Konto kustutatud",
|
||||||
"empty_column.account_timeline": "Siin postitusi ei ole!",
|
"empty_column.account_timeline": "Siin postitusi ei ole!",
|
||||||
|
|||||||
@ -355,7 +355,6 @@
|
|||||||
"emoji_button.search_results": "Bilaketaren emaitzak",
|
"emoji_button.search_results": "Bilaketaren emaitzak",
|
||||||
"emoji_button.symbols": "Sinboloak",
|
"emoji_button.symbols": "Sinboloak",
|
||||||
"emoji_button.travel": "Bidaiak eta tokiak",
|
"emoji_button.travel": "Bidaiak eta tokiak",
|
||||||
"empty_column.account_featured.other": "{acct}-ek ez du ezer nabarmendu oraindik. Ba al zenekien gehien erabiltzen dituzun traolak eta baita zure lagunen kontuak ere zure profilean nabarmendu ditzakezula?",
|
|
||||||
"empty_column.account_hides_collections": "Erabiltzaile honek informazio hau erabilgarri ez egotea aukeratu du.",
|
"empty_column.account_hides_collections": "Erabiltzaile honek informazio hau erabilgarri ez egotea aukeratu du.",
|
||||||
"empty_column.account_suspended": "Kanporatutako kontua",
|
"empty_column.account_suspended": "Kanporatutako kontua",
|
||||||
"empty_column.account_timeline": "Ez dago bidalketarik hemen!",
|
"empty_column.account_timeline": "Ez dago bidalketarik hemen!",
|
||||||
|
|||||||
@ -355,7 +355,6 @@
|
|||||||
"emoji_button.search_results": "نتایج جستوجو",
|
"emoji_button.search_results": "نتایج جستوجو",
|
||||||
"emoji_button.symbols": "نمادها",
|
"emoji_button.symbols": "نمادها",
|
||||||
"emoji_button.travel": "سفر و مکان",
|
"emoji_button.travel": "سفر و مکان",
|
||||||
"empty_column.account_featured.other": "{acct} هنوز هیچ چیزی را پیشنهاد نکرده است. آیا میدانستید که میتوانید برچسبهایی را که بیشتر استفاده میکنید و حتی حسابهای کاربری دوستانتان را در نمایه خود پیشنهاد کنید؟",
|
|
||||||
"empty_column.account_hides_collections": "کاربر خواسته که این اطّلاعات در دسترس نباشند",
|
"empty_column.account_hides_collections": "کاربر خواسته که این اطّلاعات در دسترس نباشند",
|
||||||
"empty_column.account_suspended": "حساب معلق شد",
|
"empty_column.account_suspended": "حساب معلق شد",
|
||||||
"empty_column.account_timeline": "هیچ فرستهای اینجا نیست!",
|
"empty_column.account_timeline": "هیچ فرستهای اینجا نیست!",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "Esittelyssä",
|
"account.featured": "Esittelyssä",
|
||||||
"account.featured.accounts": "Profiilit",
|
"account.featured.accounts": "Profiilit",
|
||||||
"account.featured.collections": "Kokoelmat",
|
"account.featured.collections": "Kokoelmat",
|
||||||
|
"account.featured.new_collection": "Uusi kokoelma",
|
||||||
"account.field_overflow": "Näytä koko sisältö",
|
"account.field_overflow": "Näytä koko sisältö",
|
||||||
"account.filters.all": "Kaikki toiminta",
|
"account.filters.all": "Kaikki toiminta",
|
||||||
"account.filters.boosts_toggle": "Näytä tehostukset",
|
"account.filters.boosts_toggle": "Näytä tehostukset",
|
||||||
@ -416,7 +417,6 @@
|
|||||||
"column.about": "Tietoja",
|
"column.about": "Tietoja",
|
||||||
"column.blocks": "Estetyt käyttäjät",
|
"column.blocks": "Estetyt käyttäjät",
|
||||||
"column.bookmarks": "Kirjanmerkit",
|
"column.bookmarks": "Kirjanmerkit",
|
||||||
"column.collections": "Omat kokoelmat",
|
|
||||||
"column.community": "Paikallinen aikajana",
|
"column.community": "Paikallinen aikajana",
|
||||||
"column.create_list": "Luo lista",
|
"column.create_list": "Luo lista",
|
||||||
"column.direct": "Yksityismaininnat",
|
"column.direct": "Yksityismaininnat",
|
||||||
@ -432,7 +432,9 @@
|
|||||||
"column.list_members": "Hallitse listan jäseniä",
|
"column.list_members": "Hallitse listan jäseniä",
|
||||||
"column.lists": "Listat",
|
"column.lists": "Listat",
|
||||||
"column.mutes": "Mykistetyt käyttäjät",
|
"column.mutes": "Mykistetyt käyttäjät",
|
||||||
|
"column.my_collections": "Omat kokoelmat",
|
||||||
"column.notifications": "Ilmoitukset",
|
"column.notifications": "Ilmoitukset",
|
||||||
|
"column.other_collections": "Käyttäjän {name} kokoelmat",
|
||||||
"column.pins": "Kiinnitetyt julkaisut",
|
"column.pins": "Kiinnitetyt julkaisut",
|
||||||
"column.public": "Yleinen aikajana",
|
"column.public": "Yleinen aikajana",
|
||||||
"column_back_button.label": "Takaisin",
|
"column_back_button.label": "Takaisin",
|
||||||
@ -502,6 +504,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Seuraa ja lisää listaan",
|
"confirmations.follow_to_list.confirm": "Seuraa ja lisää listaan",
|
||||||
"confirmations.follow_to_list.message": "Sinun on seurattava käyttäjää {name}, jotta voit lisätä hänet listaan.",
|
"confirmations.follow_to_list.message": "Sinun on seurattava käyttäjää {name}, jotta voit lisätä hänet listaan.",
|
||||||
"confirmations.follow_to_list.title": "Seurataanko käyttäjää?",
|
"confirmations.follow_to_list.title": "Seurataanko käyttäjää?",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Piilota välilehti",
|
||||||
|
"confirmations.hide_featured_tab.intro": "Voit muuttaa tätä milloin tahansa kohdasta <i>Muokkaa profiilia > Profiilin välilehtien asetukset</i>.",
|
||||||
|
"confirmations.hide_featured_tab.message": "Tämä piilottaa välilehden palvelimen {serverName} käyttäjiltä ja muilta palvelimilta, jotka toimivat Mastodonin uusimmalla versiolla. Muut näkymät voivat vaihdella.",
|
||||||
|
"confirmations.hide_featured_tab.title": "Piilotetaanko Esittelyssä-välilehti?",
|
||||||
"confirmations.logout.confirm": "Kirjaudu ulos",
|
"confirmations.logout.confirm": "Kirjaudu ulos",
|
||||||
"confirmations.logout.message": "Haluatko varmasti kirjautua ulos?",
|
"confirmations.logout.message": "Haluatko varmasti kirjautua ulos?",
|
||||||
"confirmations.logout.title": "Kirjaudutaanko ulos?",
|
"confirmations.logout.title": "Kirjaudutaanko ulos?",
|
||||||
@ -606,14 +612,13 @@
|
|||||||
"emoji_button.search_results": "Hakutulokset",
|
"emoji_button.search_results": "Hakutulokset",
|
||||||
"emoji_button.symbols": "Symbolit",
|
"emoji_button.symbols": "Symbolit",
|
||||||
"emoji_button.travel": "Matkailu ja paikat",
|
"emoji_button.travel": "Matkailu ja paikat",
|
||||||
"empty_column.account_featured.other": "{acct} ei esittele vielä mitään. Tiesitkö, että voit esitellä profiilissasi eniten käyttämiäsi aihetunnisteita ja jopa ystäviesi tilejä?",
|
"empty_column.account_featured.other": "{acct} ei esittele vielä mitään.",
|
||||||
"empty_column.account_featured_other.no_collections_desc": "{acct} ei ole luonut vielä yhtään kokoelmaa.",
|
|
||||||
"empty_column.account_featured_other.title": "Täällä ei mitään nähtävää",
|
|
||||||
"empty_column.account_featured_self.no_collections": "Ei vielä kokoelmia",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Luo kokoelma",
|
"empty_column.account_featured_self.no_collections_button": "Luo kokoelma",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "Piilota tämä välilehti sen sijaan",
|
||||||
"empty_column.account_featured_self.pre_collections": "Ole valmiina kokoelmiin",
|
"empty_column.account_featured_self.pre_collections": "Ole valmiina kokoelmiin",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Kokoelmien (tulossa Mastodon 4.6:ssa) avulla voit luoda valikoidun listan muille suosittelemiasi tilejä.",
|
"empty_column.account_featured_self.pre_collections_desc": "Kokoelmien (tulossa Mastodon 4.6:ssa) avulla voit luoda valikoidun listan muille suosittelemistasi tileistä.",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Tämä tili ei ole luonut vielä yhtään kokoelmaa.",
|
"empty_column.account_featured_self.showcase_accounts": "Esittele suosikkitilejäsi",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "Kokoelmat ovat valikoituja listoja tileistä, jotka auttavat muita löytämään enemmän fediversumissa.",
|
||||||
"empty_column.account_featured_unknown.other": "Tämä tili ei esittele vielä mitään.",
|
"empty_column.account_featured_unknown.other": "Tämä tili ei esittele vielä mitään.",
|
||||||
"empty_column.account_hides_collections": "Käyttäjä on päättänyt pitää nämä tiedot yksityisinä",
|
"empty_column.account_hides_collections": "Käyttäjä on päättänyt pitää nämä tiedot yksityisinä",
|
||||||
"empty_column.account_suspended": "Tili jäädytetty",
|
"empty_column.account_suspended": "Tili jäädytetty",
|
||||||
|
|||||||
@ -326,7 +326,6 @@
|
|||||||
"column.about": "Um",
|
"column.about": "Um",
|
||||||
"column.blocks": "Bannaðir brúkarar",
|
"column.blocks": "Bannaðir brúkarar",
|
||||||
"column.bookmarks": "Bókamerki",
|
"column.bookmarks": "Bókamerki",
|
||||||
"column.collections": "Míni søvn",
|
|
||||||
"column.community": "Lokal tíðarlinja",
|
"column.community": "Lokal tíðarlinja",
|
||||||
"column.create_list": "Ger lista",
|
"column.create_list": "Ger lista",
|
||||||
"column.direct": "Privatar umrøður",
|
"column.direct": "Privatar umrøður",
|
||||||
@ -504,7 +503,6 @@
|
|||||||
"emoji_button.search_results": "Leitiúrslit",
|
"emoji_button.search_results": "Leitiúrslit",
|
||||||
"emoji_button.symbols": "Ímyndir",
|
"emoji_button.symbols": "Ímyndir",
|
||||||
"emoji_button.travel": "Ferðing og støð",
|
"emoji_button.travel": "Ferðing og støð",
|
||||||
"empty_column.account_featured.other": "{acct} hevur ikki tikið nakað fram enn. Visti tú, at tú kanst taka fram tey frámerki, tú brúkar mest, og sjálvt kontur hjá vinum tínum á vangan hjá tær?",
|
|
||||||
"empty_column.account_hides_collections": "Hesin brúkarin hevur valt, at hesar upplýsingarnar ikki skulu vera tøkar",
|
"empty_column.account_hides_collections": "Hesin brúkarin hevur valt, at hesar upplýsingarnar ikki skulu vera tøkar",
|
||||||
"empty_column.account_suspended": "Kontan gjørd óvirkin",
|
"empty_column.account_suspended": "Kontan gjørd óvirkin",
|
||||||
"empty_column.account_timeline": "Einki uppslag her!",
|
"empty_column.account_timeline": "Einki uppslag her!",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "En vedette",
|
"account.featured": "En vedette",
|
||||||
"account.featured.accounts": "Profils",
|
"account.featured.accounts": "Profils",
|
||||||
"account.featured.collections": "Collections",
|
"account.featured.collections": "Collections",
|
||||||
|
"account.featured.new_collection": "Nouvelle collection",
|
||||||
"account.field_overflow": "Voir tout",
|
"account.field_overflow": "Voir tout",
|
||||||
"account.filters.all": "Toutes les activités",
|
"account.filters.all": "Toutes les activités",
|
||||||
"account.filters.boosts_toggle": "Afficher les partages",
|
"account.filters.boosts_toggle": "Afficher les partages",
|
||||||
@ -416,7 +417,6 @@
|
|||||||
"column.about": "À propos",
|
"column.about": "À propos",
|
||||||
"column.blocks": "Comptes bloqués",
|
"column.blocks": "Comptes bloqués",
|
||||||
"column.bookmarks": "Signets",
|
"column.bookmarks": "Signets",
|
||||||
"column.collections": "Mes collections",
|
|
||||||
"column.community": "Fil local",
|
"column.community": "Fil local",
|
||||||
"column.create_list": "Créer une liste",
|
"column.create_list": "Créer une liste",
|
||||||
"column.direct": "Mention privée",
|
"column.direct": "Mention privée",
|
||||||
@ -502,6 +502,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Suivre et ajouter à la liste",
|
"confirmations.follow_to_list.confirm": "Suivre et ajouter à la liste",
|
||||||
"confirmations.follow_to_list.message": "Vous devez suivre {name} pour l'ajouter à une liste.",
|
"confirmations.follow_to_list.message": "Vous devez suivre {name} pour l'ajouter à une liste.",
|
||||||
"confirmations.follow_to_list.title": "Suivre l'utilisateur·rice ?",
|
"confirmations.follow_to_list.title": "Suivre l'utilisateur·rice ?",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Cacher l'onglet",
|
||||||
|
"confirmations.hide_featured_tab.intro": "Vous pouvez modifier ce paramétrage à tout moment depuis <i>Modifier le profil > Paramètres de l'onglet du profil</i>.",
|
||||||
|
"confirmations.hide_featured_tab.message": "Cela masquera l'onglet pour les utilisateur·rice·s de {serverName} et des autres serveurs utilisant la dernière version de Mastodon. Pour les autres l'affichage peut varier.",
|
||||||
|
"confirmations.hide_featured_tab.title": "Cacher l'onglet « En vedette » ?",
|
||||||
"confirmations.logout.confirm": "Se déconnecter",
|
"confirmations.logout.confirm": "Se déconnecter",
|
||||||
"confirmations.logout.message": "Voulez-vous vraiment vous déconnecter?",
|
"confirmations.logout.message": "Voulez-vous vraiment vous déconnecter?",
|
||||||
"confirmations.logout.title": "Se déconnecter ?",
|
"confirmations.logout.title": "Se déconnecter ?",
|
||||||
@ -606,14 +610,13 @@
|
|||||||
"emoji_button.search_results": "Résultats",
|
"emoji_button.search_results": "Résultats",
|
||||||
"emoji_button.symbols": "Symboles",
|
"emoji_button.symbols": "Symboles",
|
||||||
"emoji_button.travel": "Voyage et lieux",
|
"emoji_button.travel": "Voyage et lieux",
|
||||||
"empty_column.account_featured.other": "{acct} n'a pas encore mis de contenu en avant. Saviez-vous que vous pouviez mettre en avant les hashtags que vous utilisez le plus, et même les comptes de vos amis sur votre profil ?",
|
"empty_column.account_featured.other": "{acct} n'a pas encore mis de contenu en avant.",
|
||||||
"empty_column.account_featured_other.no_collections_desc": "{acct} n'a pas encore créé de collection.",
|
|
||||||
"empty_column.account_featured_other.title": "Il n'y a rien à voir",
|
|
||||||
"empty_column.account_featured_self.no_collections": "Aucune collection pour le moment",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Créer une collection",
|
"empty_column.account_featured_self.no_collections_button": "Créer une collection",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "Cacher cet onglet",
|
||||||
"empty_column.account_featured_self.pre_collections": "Restez à l'écoute pour les collections",
|
"empty_column.account_featured_self.pre_collections": "Restez à l'écoute pour les collections",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Les collections (à venir dans Mastodon 4.6) vous permettent d'organiser vos propres listes de comptes à recommander aux autres.",
|
"empty_column.account_featured_self.pre_collections_desc": "Les collections (à venir dans Mastodon 4.6) permettent d'organiser vos propres listes de comptes à recommander aux autres.",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Ce compte n'a pas encore créé de collection.",
|
"empty_column.account_featured_self.showcase_accounts": "Présentez vos comptes préférés",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "Les collections sont des listes de comptes sélectionnés pour aider les autres à découvrir le Fédivers.",
|
||||||
"empty_column.account_featured_unknown.other": "Ce compte n'a mis aucun contenu en avant pour l'instant.",
|
"empty_column.account_featured_unknown.other": "Ce compte n'a mis aucun contenu en avant pour l'instant.",
|
||||||
"empty_column.account_hides_collections": "Cet utilisateur·ice préfère ne pas rendre publiques ces informations",
|
"empty_column.account_hides_collections": "Cet utilisateur·ice préfère ne pas rendre publiques ces informations",
|
||||||
"empty_column.account_suspended": "Compte suspendu",
|
"empty_column.account_suspended": "Compte suspendu",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "En vedette",
|
"account.featured": "En vedette",
|
||||||
"account.featured.accounts": "Profils",
|
"account.featured.accounts": "Profils",
|
||||||
"account.featured.collections": "Collections",
|
"account.featured.collections": "Collections",
|
||||||
|
"account.featured.new_collection": "Nouvelle collection",
|
||||||
"account.field_overflow": "Voir tout",
|
"account.field_overflow": "Voir tout",
|
||||||
"account.filters.all": "Toutes les activités",
|
"account.filters.all": "Toutes les activités",
|
||||||
"account.filters.boosts_toggle": "Afficher les partages",
|
"account.filters.boosts_toggle": "Afficher les partages",
|
||||||
@ -416,7 +417,6 @@
|
|||||||
"column.about": "À propos",
|
"column.about": "À propos",
|
||||||
"column.blocks": "Comptes bloqués",
|
"column.blocks": "Comptes bloqués",
|
||||||
"column.bookmarks": "Marque-pages",
|
"column.bookmarks": "Marque-pages",
|
||||||
"column.collections": "Mes collections",
|
|
||||||
"column.community": "Fil local",
|
"column.community": "Fil local",
|
||||||
"column.create_list": "Créer une liste",
|
"column.create_list": "Créer une liste",
|
||||||
"column.direct": "Mentions privées",
|
"column.direct": "Mentions privées",
|
||||||
@ -502,6 +502,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Suivre et ajouter à la liste",
|
"confirmations.follow_to_list.confirm": "Suivre et ajouter à la liste",
|
||||||
"confirmations.follow_to_list.message": "Vous devez suivre {name} pour l'ajouter à une liste.",
|
"confirmations.follow_to_list.message": "Vous devez suivre {name} pour l'ajouter à une liste.",
|
||||||
"confirmations.follow_to_list.title": "Suivre l'utilisateur·rice ?",
|
"confirmations.follow_to_list.title": "Suivre l'utilisateur·rice ?",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Cacher l'onglet",
|
||||||
|
"confirmations.hide_featured_tab.intro": "Vous pouvez modifier ce paramétrage à tout moment depuis <i>Modifier le profil > Paramètres de l'onglet du profil</i>.",
|
||||||
|
"confirmations.hide_featured_tab.message": "Cela masquera l'onglet pour les utilisateur·rice·s de {serverName} et des autres serveurs utilisant la dernière version de Mastodon. Pour les autres l'affichage peut varier.",
|
||||||
|
"confirmations.hide_featured_tab.title": "Cacher l'onglet « En vedette » ?",
|
||||||
"confirmations.logout.confirm": "Se déconnecter",
|
"confirmations.logout.confirm": "Se déconnecter",
|
||||||
"confirmations.logout.message": "Voulez-vous vraiment vous déconnecter ?",
|
"confirmations.logout.message": "Voulez-vous vraiment vous déconnecter ?",
|
||||||
"confirmations.logout.title": "Se déconnecter ?",
|
"confirmations.logout.title": "Se déconnecter ?",
|
||||||
@ -606,14 +610,13 @@
|
|||||||
"emoji_button.search_results": "Résultats de la recherche",
|
"emoji_button.search_results": "Résultats de la recherche",
|
||||||
"emoji_button.symbols": "Symboles",
|
"emoji_button.symbols": "Symboles",
|
||||||
"emoji_button.travel": "Voyage et lieux",
|
"emoji_button.travel": "Voyage et lieux",
|
||||||
"empty_column.account_featured.other": "{acct} n'a pas encore mis de contenu en avant. Saviez-vous que vous pouviez mettre en avant les hashtags que vous utilisez le plus, et même les comptes de vos amis sur votre profil ?",
|
"empty_column.account_featured.other": "{acct} n'a pas encore mis de contenu en avant.",
|
||||||
"empty_column.account_featured_other.no_collections_desc": "{acct} n'a pas encore créé de collection.",
|
|
||||||
"empty_column.account_featured_other.title": "Il n'y a rien à voir",
|
|
||||||
"empty_column.account_featured_self.no_collections": "Aucune collection pour le moment",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Créer une collection",
|
"empty_column.account_featured_self.no_collections_button": "Créer une collection",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "Cacher cet onglet",
|
||||||
"empty_column.account_featured_self.pre_collections": "Restez à l'écoute pour les collections",
|
"empty_column.account_featured_self.pre_collections": "Restez à l'écoute pour les collections",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Les collections (à venir dans Mastodon 4.6) vous permettent d'organiser vos propres listes de comptes à recommander aux autres.",
|
"empty_column.account_featured_self.pre_collections_desc": "Les collections (à venir dans Mastodon 4.6) permettent d'organiser vos propres listes de comptes à recommander aux autres.",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Ce compte n'a pas encore créé de collection.",
|
"empty_column.account_featured_self.showcase_accounts": "Présentez vos comptes préférés",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "Les collections sont des listes de comptes sélectionnés pour aider les autres à découvrir le Fédivers.",
|
||||||
"empty_column.account_featured_unknown.other": "Ce compte n'a mis aucun contenu en avant pour l'instant.",
|
"empty_column.account_featured_unknown.other": "Ce compte n'a mis aucun contenu en avant pour l'instant.",
|
||||||
"empty_column.account_hides_collections": "Cet utilisateur·ice préfère ne pas rendre publiques ces informations",
|
"empty_column.account_hides_collections": "Cet utilisateur·ice préfère ne pas rendre publiques ces informations",
|
||||||
"empty_column.account_suspended": "Compte suspendu",
|
"empty_column.account_suspended": "Compte suspendu",
|
||||||
|
|||||||
@ -285,7 +285,6 @@
|
|||||||
"emoji_button.search_results": "Sykresultaten",
|
"emoji_button.search_results": "Sykresultaten",
|
||||||
"emoji_button.symbols": "Symboalen",
|
"emoji_button.symbols": "Symboalen",
|
||||||
"emoji_button.travel": "Reizgje en lokaasjes",
|
"emoji_button.travel": "Reizgje en lokaasjes",
|
||||||
"empty_column.account_featured.other": "{acct} hat noch neat útljochte. Wisten jo dat jo jo hashtags dy’t jo it meast brûke, en sels de accounts fan dyn freonen fermelde kinne op jo profyl?",
|
|
||||||
"empty_column.account_hides_collections": "Dizze brûker hat derfoar keazen dizze ynformaasje net beskikber te meitsjen",
|
"empty_column.account_hides_collections": "Dizze brûker hat derfoar keazen dizze ynformaasje net beskikber te meitsjen",
|
||||||
"empty_column.account_suspended": "Account beskoattele",
|
"empty_column.account_suspended": "Account beskoattele",
|
||||||
"empty_column.account_timeline": "Hjir binne gjin berjochten!",
|
"empty_column.account_timeline": "Hjir binne gjin berjochten!",
|
||||||
|
|||||||
@ -416,7 +416,6 @@
|
|||||||
"column.about": "Maidir le",
|
"column.about": "Maidir le",
|
||||||
"column.blocks": "Úsáideoirí blocáilte",
|
"column.blocks": "Úsáideoirí blocáilte",
|
||||||
"column.bookmarks": "Leabharmharcanna",
|
"column.bookmarks": "Leabharmharcanna",
|
||||||
"column.collections": "Mo bhailiúcháin",
|
|
||||||
"column.community": "Amlíne áitiúil",
|
"column.community": "Amlíne áitiúil",
|
||||||
"column.create_list": "Cruthaigh liosta",
|
"column.create_list": "Cruthaigh liosta",
|
||||||
"column.direct": "Luann príobháideach",
|
"column.direct": "Luann príobháideach",
|
||||||
@ -581,7 +580,9 @@
|
|||||||
"domain_pill.your_server": "Do theach digiteach, áit a bhfuil do phoist go léir ina gcónaí. Nach maith leat an ceann seo? Aistrigh freastalaithe am ar bith agus tabhair leat do leantóirí freisin.",
|
"domain_pill.your_server": "Do theach digiteach, áit a bhfuil do phoist go léir ina gcónaí. Nach maith leat an ceann seo? Aistrigh freastalaithe am ar bith agus tabhair leat do leantóirí freisin.",
|
||||||
"domain_pill.your_username": "D'aitheantóir uathúil ar an bhfreastalaí seo. Is féidir teacht ar úsáideoirí leis an ainm úsáideora céanna ar fhreastalaithe éagsúla.",
|
"domain_pill.your_username": "D'aitheantóir uathúil ar an bhfreastalaí seo. Is féidir teacht ar úsáideoirí leis an ainm úsáideora céanna ar fhreastalaithe éagsúla.",
|
||||||
"dropdown.empty": "Roghnaigh rogha",
|
"dropdown.empty": "Roghnaigh rogha",
|
||||||
|
"email_subscriptions.email": "Ríomhphost",
|
||||||
"email_subscriptions.form.action": "Liostáil",
|
"email_subscriptions.form.action": "Liostáil",
|
||||||
|
"email_subscriptions.form.bottom": "Faigh poist i do bhosca isteach gan cuntas Mastodon a chruthú. Díliostáil ag am ar bith. Le haghaidh tuilleadh eolais, féach ar an <a>Polasaí Príobháideachta</a>.",
|
||||||
"email_subscriptions.form.title": "Cláraigh le haghaidh nuashonruithe ríomhphoist ó {name}",
|
"email_subscriptions.form.title": "Cláraigh le haghaidh nuashonruithe ríomhphoist ó {name}",
|
||||||
"email_subscriptions.submitted.lead": "Seiceáil do bhosca isteach le haghaidh ríomhphoist chun clárú le haghaidh nuashonruithe ríomhphoist a chríochnú.",
|
"email_subscriptions.submitted.lead": "Seiceáil do bhosca isteach le haghaidh ríomhphoist chun clárú le haghaidh nuashonruithe ríomhphoist a chríochnú.",
|
||||||
"email_subscriptions.submitted.title": "Céim amháin eile",
|
"email_subscriptions.submitted.title": "Céim amháin eile",
|
||||||
@ -604,14 +605,8 @@
|
|||||||
"emoji_button.search_results": "Torthaí cuardaigh",
|
"emoji_button.search_results": "Torthaí cuardaigh",
|
||||||
"emoji_button.symbols": "Comharthaí",
|
"emoji_button.symbols": "Comharthaí",
|
||||||
"emoji_button.travel": "Taisteal ⁊ Áiteanna",
|
"emoji_button.travel": "Taisteal ⁊ Áiteanna",
|
||||||
"empty_column.account_featured.other": "Níl aon rud feicthe ag {acct} go fóill. An raibh a fhios agat gur féidir leat na hashtags is mó a úsáideann tú, agus fiú cuntais do chairde, a chur ar do phróifíl?",
|
|
||||||
"empty_column.account_featured_other.no_collections_desc": "Níl aon bhailiúcháin cruthaithe ag {acct} go fóill.",
|
|
||||||
"empty_column.account_featured_other.title": "Níl aon rud le feiceáil anseo",
|
|
||||||
"empty_column.account_featured_self.no_collections": "Gan aon bhailiúcháin fós",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Cruthaigh bailiúchán",
|
"empty_column.account_featured_self.no_collections_button": "Cruthaigh bailiúchán",
|
||||||
"empty_column.account_featured_self.pre_collections": "Fan tiúnta le haghaidh bailiúcháin",
|
"empty_column.account_featured_self.pre_collections": "Fan tiúnta le haghaidh bailiúcháin",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Le bailiúcháin (atá ag teacht i Mastodon 4.6) is féidir leat do liostaí cuntas féin a chruthú le moladh do dhaoine eile.",
|
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Níl aon bhailiúcháin cruthaithe ag an gcuntas seo go fóill.",
|
|
||||||
"empty_column.account_featured_unknown.other": "Níl aon rud le feiceáil ar an gcuntas seo go fóill.",
|
"empty_column.account_featured_unknown.other": "Níl aon rud le feiceáil ar an gcuntas seo go fóill.",
|
||||||
"empty_column.account_hides_collections": "Roghnaigh an t-úsáideoir seo gan an fhaisnéis seo a chur ar fáil",
|
"empty_column.account_hides_collections": "Roghnaigh an t-úsáideoir seo gan an fhaisnéis seo a chur ar fáil",
|
||||||
"empty_column.account_suspended": "Cuntas ar fionraí",
|
"empty_column.account_suspended": "Cuntas ar fionraí",
|
||||||
|
|||||||
@ -416,7 +416,6 @@
|
|||||||
"column.about": "Mu dhèidhinn",
|
"column.about": "Mu dhèidhinn",
|
||||||
"column.blocks": "Cleachdaichean bacte",
|
"column.blocks": "Cleachdaichean bacte",
|
||||||
"column.bookmarks": "Comharran-lìn",
|
"column.bookmarks": "Comharran-lìn",
|
||||||
"column.collections": "Na cruinneachaidhean agam",
|
|
||||||
"column.community": "Loidhne-ama ionadail",
|
"column.community": "Loidhne-ama ionadail",
|
||||||
"column.create_list": "Cruthaich liosta",
|
"column.create_list": "Cruthaich liosta",
|
||||||
"column.direct": "Iomraidhean prìobhaideach",
|
"column.direct": "Iomraidhean prìobhaideach",
|
||||||
@ -605,12 +604,7 @@
|
|||||||
"emoji_button.search_results": "Toraidhean an luirg",
|
"emoji_button.search_results": "Toraidhean an luirg",
|
||||||
"emoji_button.symbols": "Samhlaidhean",
|
"emoji_button.symbols": "Samhlaidhean",
|
||||||
"emoji_button.travel": "Siubhal ⁊ àitichean",
|
"emoji_button.travel": "Siubhal ⁊ àitichean",
|
||||||
"empty_column.account_featured.other": "Chan eil {acct} a’ brosnachadh dad fhathast. An robh fios agad gur urrainn dhut na tagaichean hais a chleachdas tu as trice agus fiù ’s cunntasan do charaidean a bhrosnachadh air a’ phròifil agad?",
|
|
||||||
"empty_column.account_featured_other.no_collections_desc": "Cha do chruthaich {acct} cruinneachadh sam bith fhathast.",
|
|
||||||
"empty_column.account_featured_other.title": "Chan eil dad ri fhaicinn an-seo",
|
|
||||||
"empty_column.account_featured_self.no_collections": "Chan eil cruinneachadh ann fhathast",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Cruthaich cruinneachadh",
|
"empty_column.account_featured_self.no_collections_button": "Cruthaich cruinneachadh",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Cha do chruthaich an cunntas seo cruinneachadh sam bith fhathast.",
|
|
||||||
"empty_column.account_featured_unknown.other": "Chan eil an cunntas seo a’ brosnachadh dad fhathast.",
|
"empty_column.account_featured_unknown.other": "Chan eil an cunntas seo a’ brosnachadh dad fhathast.",
|
||||||
"empty_column.account_hides_collections": "Chuir an cleachdaiche seo roimhe nach eil am fiosrachadh seo ri fhaighinn",
|
"empty_column.account_hides_collections": "Chuir an cleachdaiche seo roimhe nach eil am fiosrachadh seo ri fhaighinn",
|
||||||
"empty_column.account_suspended": "Chaidh an cunntas a chur à rèim",
|
"empty_column.account_suspended": "Chaidh an cunntas a chur à rèim",
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"account.featured": "Destacado",
|
"account.featured": "Destacado",
|
||||||
"account.featured.accounts": "Perfís",
|
"account.featured.accounts": "Perfís",
|
||||||
"account.featured.collections": "Coleccións",
|
"account.featured.collections": "Coleccións",
|
||||||
|
"account.featured.new_collection": "Nova colección",
|
||||||
"account.field_overflow": "Mostrar contido completo",
|
"account.field_overflow": "Mostrar contido completo",
|
||||||
"account.filters.all": "Toda actividade",
|
"account.filters.all": "Toda actividade",
|
||||||
"account.filters.boosts_toggle": "Mostrar promocións",
|
"account.filters.boosts_toggle": "Mostrar promocións",
|
||||||
@ -416,7 +417,6 @@
|
|||||||
"column.about": "Sobre",
|
"column.about": "Sobre",
|
||||||
"column.blocks": "Usuarias bloqueadas",
|
"column.blocks": "Usuarias bloqueadas",
|
||||||
"column.bookmarks": "Marcadores",
|
"column.bookmarks": "Marcadores",
|
||||||
"column.collections": "As miñas coleccións",
|
|
||||||
"column.community": "Cronoloxía local",
|
"column.community": "Cronoloxía local",
|
||||||
"column.create_list": "Crear lista",
|
"column.create_list": "Crear lista",
|
||||||
"column.direct": "Mencións privadas",
|
"column.direct": "Mencións privadas",
|
||||||
@ -432,7 +432,9 @@
|
|||||||
"column.list_members": "Xestionar membros da lista",
|
"column.list_members": "Xestionar membros da lista",
|
||||||
"column.lists": "Listaxes",
|
"column.lists": "Listaxes",
|
||||||
"column.mutes": "Usuarias acaladas",
|
"column.mutes": "Usuarias acaladas",
|
||||||
|
"column.my_collections": "As miñas coleccións",
|
||||||
"column.notifications": "Notificacións",
|
"column.notifications": "Notificacións",
|
||||||
|
"column.other_collections": "Coleccións de {name}",
|
||||||
"column.pins": "Publicacións fixadas",
|
"column.pins": "Publicacións fixadas",
|
||||||
"column.public": "Cronoloxía federada",
|
"column.public": "Cronoloxía federada",
|
||||||
"column_back_button.label": "Volver",
|
"column_back_button.label": "Volver",
|
||||||
@ -502,6 +504,10 @@
|
|||||||
"confirmations.follow_to_list.confirm": "Seguir e engadir á lista",
|
"confirmations.follow_to_list.confirm": "Seguir e engadir á lista",
|
||||||
"confirmations.follow_to_list.message": "Tes que seguir a {name} para poder engadila a unha lista.",
|
"confirmations.follow_to_list.message": "Tes que seguir a {name} para poder engadila a unha lista.",
|
||||||
"confirmations.follow_to_list.title": "Seguir á usuaria?",
|
"confirmations.follow_to_list.title": "Seguir á usuaria?",
|
||||||
|
"confirmations.hide_featured_tab.confirm": "Ocultar pestana",
|
||||||
|
"confirmations.hide_featured_tab.intro": "Podes cambiar isto cando queiras nos axustes en <i>Editar perfil > pestana Perfil</i>.",
|
||||||
|
"confirmations.hide_featured_tab.message": "Vas ocultar a pestana para as usuarias de {serverName} e outros servidores que usen a última versión de Mastodon. Noutros lugares podería ser diferente.",
|
||||||
|
"confirmations.hide_featured_tab.title": "Ocultar a pestana «Destacado»?",
|
||||||
"confirmations.logout.confirm": "Pechar sesión",
|
"confirmations.logout.confirm": "Pechar sesión",
|
||||||
"confirmations.logout.message": "Desexas pechar a sesión?",
|
"confirmations.logout.message": "Desexas pechar a sesión?",
|
||||||
"confirmations.logout.title": "Pechar sesión?",
|
"confirmations.logout.title": "Pechar sesión?",
|
||||||
@ -583,6 +589,7 @@
|
|||||||
"dropdown.empty": "Escolle unha opción",
|
"dropdown.empty": "Escolle unha opción",
|
||||||
"email_subscriptions.email": "Correo electrónico",
|
"email_subscriptions.email": "Correo electrónico",
|
||||||
"email_subscriptions.form.action": "Subscribirse",
|
"email_subscriptions.form.action": "Subscribirse",
|
||||||
|
"email_subscriptions.form.bottom": "Recibe publicacións no teu correo sen precisar crear unha conta de Mastodon. Date de baixa cando queiras. Máis información na <a>Directiva de privacidade</a>.",
|
||||||
"email_subscriptions.form.title": "Subscríbete para recibir actualizacións por correo de {name}",
|
"email_subscriptions.form.title": "Subscríbete para recibir actualizacións por correo de {name}",
|
||||||
"email_subscriptions.submitted.lead": "Comproba a túa caixa de correo para completar a subscrición ás actualizacións por correo.",
|
"email_subscriptions.submitted.lead": "Comproba a túa caixa de correo para completar a subscrición ás actualizacións por correo.",
|
||||||
"email_subscriptions.submitted.title": "Un último paso",
|
"email_subscriptions.submitted.title": "Un último paso",
|
||||||
@ -605,14 +612,13 @@
|
|||||||
"emoji_button.search_results": "Resultados da procura",
|
"emoji_button.search_results": "Resultados da procura",
|
||||||
"emoji_button.symbols": "Símbolos",
|
"emoji_button.symbols": "Símbolos",
|
||||||
"emoji_button.travel": "Viaxes e Lugares",
|
"emoji_button.travel": "Viaxes e Lugares",
|
||||||
"empty_column.account_featured.other": "{acct} aínda non escolleu nada para destacar. Sabías que podes facer destacatar no teu perfil os cancelos que máis usas, incluso os perfís das túas amizades?",
|
"empty_column.account_featured.other": "{acct} aínda non destacou nada.",
|
||||||
"empty_column.account_featured_other.no_collections_desc": "{acct} aínda non creou ningunha colección.",
|
|
||||||
"empty_column.account_featured_other.title": "Non hai nada que ver aquí",
|
|
||||||
"empty_column.account_featured_self.no_collections": "Aínda non tes coleccións",
|
|
||||||
"empty_column.account_featured_self.no_collections_button": "Crea unha colección",
|
"empty_column.account_featured_self.no_collections_button": "Crea unha colección",
|
||||||
|
"empty_column.account_featured_self.no_collections_hide_tab": "Ocultar esta pestana entonces",
|
||||||
"empty_column.account_featured_self.pre_collections": "Van chegar as Coleccións",
|
"empty_column.account_featured_self.pre_collections": "Van chegar as Coleccións",
|
||||||
"empty_column.account_featured_self.pre_collections_desc": "Coas Coleccións (a partir de Mastodon 4.6) podes crear as túas listas persoais de contas para recomendar a outras persoas.",
|
"empty_column.account_featured_self.pre_collections_desc": "Coas Coleccións (a partir de Mastodon 4.6) podes crear as túas listas persoais de contas para recomendar a outras persoas.",
|
||||||
"empty_column.account_featured_unknown.no_collections_desc": "Esta conta aínda non creou ningunha colección.",
|
"empty_column.account_featured_self.showcase_accounts": "Salienta as túas contas favoritas",
|
||||||
|
"empty_column.account_featured_self.showcase_accounts_desc": "As coleccións son listas de contas para que outras persoas as coñezan e desfruten aquí no Fediverso.",
|
||||||
"empty_column.account_featured_unknown.other": "Esta conta aínda non destacou nada.",
|
"empty_column.account_featured_unknown.other": "Esta conta aínda non destacou nada.",
|
||||||
"empty_column.account_hides_collections": "A usuaria decideu non facer pública esta información",
|
"empty_column.account_hides_collections": "A usuaria decideu non facer pública esta información",
|
||||||
"empty_column.account_suspended": "Conta suspendida",
|
"empty_column.account_suspended": "Conta suspendida",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user