From 2508370f44272719c24bd8639f1b58bd24d01be2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 5 May 2019 17:14:15 +0200 Subject: [PATCH 01/23] Bump version to 2.8.2 (#10703) --- CHANGELOG.md | 12 ++++++++++++ lib/mastodon/version.rb | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9639aed086..222b7411d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,18 @@ Changelog All notable changes to this project will be documented in this file. +## [2.8.2] - 2019-05-05 +### Added + +- Add `SOURCE_TAG` environment variable ([ushitora-anqou](https://github.com/tootsuite/mastodon/pull/10698)) + +### Fixed + +- Fix cropped hero image on frontpage ([BaptisteGelez](https://github.com/tootsuite/mastodon/pull/10702)) +- Fix blurhash gem not compiling on some operating systems ([Gargron](https://github.com/tootsuite/mastodon/pull/10700)) +- Fix unexpected CSS animations in some browsers ([ThibG](https://github.com/tootsuite/mastodon/pull/10699)) +- Fix closing video modal scrolling timelines to top ([ThibG](https://github.com/tootsuite/mastodon/pull/10695)) + ## [2.8.1] - 2019-05-04 ### Added diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index 127c510485..91f45e45de 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -13,7 +13,7 @@ module Mastodon end def patch - 1 + 2 end def pre From e742bff19b609c2ac43f87d62cd2ed948471d5a0 Mon Sep 17 00:00:00 2001 From: jeroenpraat <41594439+jeroenpraat@users.noreply.github.com> Date: Sun, 5 May 2019 21:33:24 +0200 Subject: [PATCH 02/23] 1 NL string update (#10709) * 1 NL string update No that weblate isn't used anymore, it would be fine if, or the english strings are update, or there is somewhere an explanation how to generate new strings for a language * Update nl.json --- app/javascript/mastodon/locales/nl.json | 1 + 1 file changed, 1 insertion(+) diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 96e39356b7..497a11d5c3 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -77,6 +77,7 @@ "compose_form.poll.remove_option": "Deze keuze verwijderen", "compose_form.publish": "Toot", "compose_form.publish_loud": "{publish}!", + "compose_form.sensitive.hide": "Media als gevoelig markeren", "compose_form.sensitive.marked": "Media is als gevoelig gemarkeerd", "compose_form.sensitive.unmarked": "Media is niet als gevoelig gemarkeerd", "compose_form.spoiler.marked": "Tekst is achter een waarschuwing verborgen", From 1eb14ef7740001e897d5f2d7976cbb643800f428 Mon Sep 17 00:00:00 2001 From: mayaeh Date: Mon, 6 May 2019 04:34:32 +0900 Subject: [PATCH 03/23] i18n: Update Japanese translations (#10706) * Update Japanese translations. run yarn manage:translations This commit includes translations by some users that were done at the transifex. * Reduce translation text because it becomes two lines. --- .../mastodon/locales/defaultMessages.json | 25 +++++++++++++------ app/javascript/mastodon/locales/en.json | 3 ++- app/javascript/mastodon/locales/ja.json | 3 ++- config/locales/devise.ja.yml | 2 +- config/locales/ja.yml | 25 ++++++++++--------- 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json index e7b4b479a2..11b6dd8543 100644 --- a/app/javascript/mastodon/locales/defaultMessages.json +++ b/app/javascript/mastodon/locales/defaultMessages.json @@ -180,10 +180,6 @@ { "defaultMessage": "Media hidden", "id": "status.media_hidden" - }, - { - "defaultMessage": "Click to view", - "id": "status.sensitive_toggle" } ], "path": "app/javascript/mastodon/components/media_gallery.json" @@ -1096,6 +1092,10 @@ { "defaultMessage": "Media is not marked as sensitive", "id": "compose_form.sensitive.unmarked" + }, + { + "defaultMessage": "Mark media as sensitive", + "id": "compose_form.sensitive.hide" } ], "path": "app/javascript/mastodon/features/compose/containers/sensitive_button_container.json" @@ -2249,6 +2249,10 @@ { "defaultMessage": "Next", "id": "lightbox.next" + }, + { + "defaultMessage": "View context", + "id": "lightbox.view_context" } ], "path": "app/javascript/mastodon/features/ui/components/media_modal.json" @@ -2341,6 +2345,15 @@ ], "path": "app/javascript/mastodon/features/ui/components/upload_area.json" }, + { + "descriptors": [ + { + "defaultMessage": "View context", + "id": "lightbox.view_context" + } + ], + "path": "app/javascript/mastodon/features/ui/components/video_modal.json" + }, { "descriptors": [ { @@ -2395,10 +2408,6 @@ { "defaultMessage": "Media hidden", "id": "status.media_hidden" - }, - { - "defaultMessage": "Click to view", - "id": "status.sensitive_toggle" } ], "path": "app/javascript/mastodon/features/video/index.json" diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index baed4939c4..272f22088d 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -77,6 +77,7 @@ "compose_form.poll.remove_option": "Remove this choice", "compose_form.publish": "Toot", "compose_form.publish_loud": "{publish}!", + "compose_form.sensitive.hide": "Mark media as sensitive", "compose_form.sensitive.marked": "Media is marked as sensitive", "compose_form.sensitive.unmarked": "Media is not marked as sensitive", "compose_form.spoiler.marked": "Text is hidden behind warning", @@ -209,6 +210,7 @@ "lightbox.close": "Close", "lightbox.next": "Next", "lightbox.previous": "Previous", + "lightbox.view_context": "View context", "lists.account.add": "Add to list", "lists.account.remove": "Remove from list", "lists.delete": "Delete list", @@ -340,7 +342,6 @@ "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", - "status.sensitive_toggle": "Click to view", "status.sensitive_warning": "Sensitive content", "status.share": "Share", "status.show_less": "Show less", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index f80988d0d4..c9e7a7b90d 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -77,6 +77,7 @@ "compose_form.poll.remove_option": "この項目を削除", "compose_form.publish": "トゥート", "compose_form.publish_loud": "{publish}!", + "compose_form.sensitive.hide": "メディアを閲覧注意にする", "compose_form.sensitive.marked": "メディアに閲覧注意が設定されています", "compose_form.sensitive.unmarked": "メディアに閲覧注意が設定されていません", "compose_form.spoiler.marked": "閲覧注意が設定されています", @@ -209,6 +210,7 @@ "lightbox.close": "閉じる", "lightbox.next": "次", "lightbox.previous": "前", + "lightbox.view_context": "トゥートを表示", "lists.account.add": "リストに追加", "lists.account.remove": "リストから外す", "lists.delete": "リストを削除", @@ -340,7 +342,6 @@ "status.reply": "返信", "status.replyAll": "全員に返信", "status.report": "@{name}さんを通報", - "status.sensitive_toggle": "クリックして表示", "status.sensitive_warning": "閲覧注意", "status.share": "共有", "status.show_less": "隠す", diff --git a/config/locales/devise.ja.yml b/config/locales/devise.ja.yml index 3dac630506..b9f2fb8a6c 100644 --- a/config/locales/devise.ja.yml +++ b/config/locales/devise.ja.yml @@ -12,7 +12,7 @@ ja: last_attempt: あと1回失敗するとアカウントがロックされます。 locked: アカウントはロックされました。 not_found_in_database: "%{authentication_keys}かパスワードが誤っています。" - pending: あなたのアカウントはまだ審査中です。 + pending: あなたのアカウントはまだ承認待ちです。 timeout: セッションの有効期限が切れました。続行するには再度ログインしてください。 unauthenticated: 続行するにはログインするか、アカウントを作成してください。 unconfirmed: 続行するにはメールアドレスを確認する必要があります。 diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 545146145c..4087e299c7 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -20,7 +20,7 @@ ja: extended_description_html: |

ルールを書くのに適した場所

詳細説明が設定されていません。

- federation_hint_html: "%{instance} にアカウントがあればどの互換性のあるサーバーのユーザーでもフォローできるでしょう。" + federation_hint_html: "%{instance} のアカウントひとつでどんなMastodon互換サーバーのユーザーでもフォローできるでしょう。" generic_description: "%{domain} は、Mastodon サーバーの一つです" get_apps: モバイルアプリを試す hosted_on: Mastodon hosted on %{domain} @@ -269,6 +269,7 @@ ja: created_msg: ドメインブロック処理を完了しました destroyed_msg: ドメインブロックを外しました domain: ドメイン + existing_domain_block_html: 既に%{name}に対しより厳しい制限を課しています 。まずはそれを解除する必要があります。 new: create: ブロックを作成 hint: ドメインブロックはデータベース中のアカウント項目の作成を妨げませんが、遡って自動的に指定されたモデレーションをそれらのアカウントに適用します。 @@ -659,7 +660,7 @@ ja: i_am_html: I am %{username} on %{service}. identity: Identity inactive: 非アクティブ - publicize_checkbox: 'そしてこれをトゥートしてください:' + publicize_checkbox: 'そしてこれをトゥートします:' publicize_toot: 'It is proven! I am %{username} on %{service}: %{url}' status: 認証状態 view_proof: 証明を表示 @@ -1049,21 +1050,21 @@ ja: suspend: アカウントが停止されました welcome: edit_profile_action: プロフィールを設定 - edit_profile_step: アバター画像やヘッダー画像をアップロードしたり、表示名やその他プロフィールを変更しカスタマイズすることができます。新しいフォロワーからのフォローを許可する前に検討したい場合、アカウントを承認制にすることができます。 + edit_profile_step: アイコンやヘッダーの画像をアップロードしたり、表示名を変更したりして、自分のプロフィールをカスタマイズすることができます。また、誰かからの新規フォローを許可する前にその人の様子を見ておきたい場合、アカウントを承認制にすることもできます。 explanation: 始めるにあたってのアドバイスです final_action: 始めましょう - final_step: 'さあ始めましょう! たとえフォロワーがいなくても、あなたの公開した投稿はローカルタイムラインやハッシュタグなどで誰かの目に止まるかもしれません。自己紹介をしたい時は #introductions ハッシュタグを使うといいかもしれません。' - full_handle: あなたの正式なユーザー名 - full_handle_hint: これは別のサーバーからフォローしてもらったりメッセージのやり取りをする際に、友達に伝えるといいでしょう。 + final_step: 'さあ、始めましょう! たとえフォロワーがまだいなくても、あなたの公開した投稿はローカルタイムラインやハッシュタグなどを通じて誰かの目にとまるはずです。自己紹介をしたいときには #introductions ハッシュタグが便利かもしれません。' + full_handle: あなたの正式なユーザーID + full_handle_hint: 別のサーバーの友達とフォローやメッセージをやり取りする際には、これを伝えることになります。 review_preferences_action: 設定の変更 - review_preferences_step: 受け取りたいメールや投稿の公開範囲などの設定を必ず行ってください。不快でないならアニメーション GIF の自動再生を有効にすることもできます。 + review_preferences_step: 受け取りたいメールの種類や投稿のデフォルト公開範囲など、ユーザー設定を必ず済ませておきましょう。目が回らない自信があるなら、アニメーション GIF を自動再生する設定もご検討ください。 subject: Mastodon へようこそ - tip_federated_timeline: 連合タイムラインは Mastodon ネットワークの流れを見られるものです。ただしあなたと同じサーバーの人がフォローしている人だけが含まれるので、それが全てではありません。 - tip_following: 標準では自動でサーバーの管理者をフォローしています。もっと興味のある人たちを見つけるには、ローカルタイムラインと連合タイムラインを確認してください。 - tip_local_timeline: ローカルタイムラインは %{instance} にいる人々の流れを見られるものです。彼らはあなたと同じサーバーにいる隣人のようなものです! - tip_mobile_webapp: もしモバイル端末のブラウザで Mastodon をホーム画面に追加できる場合、プッシュ通知を受け取ることができます。それはまるでネイティブアプリのように動作します! + tip_federated_timeline: 連合タイムラインは、Mastodon ネットワークによる巨大流しそうめんです。ただし、あなたの「隣人」達がフォローしている人々だけが流れてくる場所なので、決してそこに全てがあるわけではありません。 + tip_following: 最初は、サーバーの管理者をフォローした状態になっています。もっと興味のある人たちを見つけるには、ローカルタイムラインと連合タイムラインを確認してみましょう。 + tip_local_timeline: ローカルタイムラインには、%{instance} にいる人々が流しそうめんのごとく流れてきます。彼らはあなたと同じサーバーに暮らす、愛すべき隣人です! + tip_mobile_webapp: お使いのモバイル端末で、ブラウザから Mastodon をホーム画面に追加できますか? もし追加できる場合、プッシュ通知の受け取りなど、まるで「普通の」アプリのような機能が楽しめます! tips: 豆知識 - title: ようこそ、%{name} ! + title: ようこそ、%{name}! users: follow_limit_reached: あなたは現在 %{limit} 人以上フォローできません invalid_email: メールアドレスが無効です From b2f5b1045fd84b692721bf44652d569d63d17657 Mon Sep 17 00:00:00 2001 From: ThibG Date: Mon, 6 May 2019 05:33:56 +0200 Subject: [PATCH 04/23] Add description on hover in media gallery (#10713) --- .../mastodon/features/account_gallery/components/media_item.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/account_gallery/components/media_item.js b/app/javascript/mastodon/features/account_gallery/components/media_item.js index 5643e64490..f44e209398 100644 --- a/app/javascript/mastodon/features/account_gallery/components/media_item.js +++ b/app/javascript/mastodon/features/account_gallery/components/media_item.js @@ -88,6 +88,7 @@ export default class MediaItem extends ImmutablePureComponent { const width = `${Math.floor((displayWidth - 4) / 3) - 4}px`; const height = width; const status = attachment.get('status'); + const title = status.get('spoiler_text') || attachment.get('description'); let thumbnail = ''; @@ -133,7 +134,7 @@ export default class MediaItem extends ImmutablePureComponent { return (
- + {visible && thumbnail} From 7e73a8b8bfe46c0a70c715b8e1c0d765899356a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 May 2019 15:12:55 +0900 Subject: [PATCH 05/23] Bump parallel_tests from 2.28.0 to 2.29.0 (#10716) Bumps [parallel_tests](https://github.com/grosser/parallel_tests) from 2.28.0 to 2.29.0. - [Release notes](https://github.com/grosser/parallel_tests/releases) - [Commits](https://github.com/grosser/parallel_tests/compare/v2.28.0...v2.29.0) Signed-off-by: dependabot[bot] --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index db00c24fb9..998a6b8166 100644 --- a/Gemfile +++ b/Gemfile @@ -116,7 +116,7 @@ group :test do gem 'rspec-sidekiq', '~> 3.0' gem 'simplecov', '~> 0.16', require: false gem 'webmock', '~> 3.5' - gem 'parallel_tests', '~> 2.28' + gem 'parallel_tests', '~> 2.29' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 59b34a185c..ec8bc18574 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -393,7 +393,7 @@ GEM av (~> 0.9.0) paperclip (>= 2.5.2) parallel (1.17.0) - parallel_tests (2.28.0) + parallel_tests (2.29.0) parallel parser (2.6.3.0) ast (~> 2.4.0) @@ -724,7 +724,7 @@ DEPENDENCIES ox (~> 2.10) paperclip (~> 6.0) paperclip-av-transcoder (~> 0.6) - parallel_tests (~> 2.28) + parallel_tests (~> 2.29) pg (~> 1.1) pghero (~> 2.2) pkg-config (~> 1.3) From 7562602df8a889ed70efede52bed86e2d1bf8a5d Mon Sep 17 00:00:00 2001 From: spla Date: Mon, 6 May 2019 17:55:37 +0200 Subject: [PATCH 06/23] i18n Update Catalan translation (#10719) * Updated Catalan strings * Update ca.yml * Update ca.yml * Update ca.yml * Update ca.yml * Update ca.yml * Update ca.yml * Update ca.yml * Update simple_form.ca.yml * Update simple_form.ca.yml * Update simple_form.ca.yml * bundle exec i18n-tasks * Update ca.json * Update simple_form.ca.yml * i18n: Update Catalan translations * i18n: Update Catalan translations * i18n: Update Catalan translations * i18n: Update Catalan translations * i18n: Update Catalan translations * i18n: Update Catalan translations * i18n: Update Catalan translations * i18n: Update Catalan translations * i18n: Update Catalan translations * i18n: Update Catalan translation * i18n Update Catalan translation --- app/javascript/mastodon/locales/ca.json | 9 +++++---- config/locales/ca.yml | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 18dd56d0df..0cafb11203 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -17,7 +17,7 @@ "account.hide_reblogs": "Amaga els impulsos de @{name}", "account.link_verified_on": "La propietat d'aquest enllaç es va verificar el dia {date}", "account.locked_info": "Aquest estat de privadesa del compte està definit com a bloquejat. El propietari revisa manualment qui pot seguir-lo.", - "account.media": "Media", + "account.media": "Mèdia", "account.mention": "Esmentar @{name}", "account.moved_to": "{name} s'ha mogut a:", "account.mute": "Silencia @{name}", @@ -77,6 +77,7 @@ "compose_form.poll.remove_option": "Elimina aquesta opció", "compose_form.publish": "Toot", "compose_form.publish_loud": "{publish}!", + "compose_form.sensitive.hide": "Marcar mèdia com a sensible", "compose_form.sensitive.marked": "Mèdia marcat com a sensible", "compose_form.sensitive.unmarked": "Mèdia no està marcat com a sensible", "compose_form.spoiler.marked": "Text es ocult sota l'avís", @@ -85,7 +86,7 @@ "confirmation_modal.cancel": "Cancel·la", "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Bloca", - "confirmations.block.message": "Estàs segur que vols blocar {name}?", + "confirmations.block.message": "Estàs segur que vols bloquejar a {name}?", "confirmations.delete.confirm": "Suprimeix", "confirmations.delete.message": "Estàs segur que vols suprimir aquest estat?", "confirmations.delete_list.confirm": "Suprimeix", @@ -125,7 +126,7 @@ "empty_column.favourited_statuses": "Encara no tens cap toot favorit. Quan en tinguis, apareixerà aquí.", "empty_column.favourites": "Encara ningú ha marcat aquest toot com a favorit. Quan algú ho faci, apareixera aquí.", "empty_column.follow_requests": "Encara no teniu cap petició de seguiment. Quan rebeu una, apareixerà aquí.", - "empty_column.hashtag": "Encara no hi ha res amb aquesta etiqueta.", + "empty_column.hashtag": "Encara no hi ha res en aquesta etiqueta.", "empty_column.home": "Encara no segueixes ningú. Visita {public} o fes cerca per començar i conèixer altres usuaris.", "empty_column.home.public_timeline": "la línia de temps pública", "empty_column.list": "Encara no hi ha res en aquesta llista. Quan els membres d'aquesta llista publiquin nous estats, apareixeran aquí.", @@ -209,6 +210,7 @@ "lightbox.close": "Tancar", "lightbox.next": "Següent", "lightbox.previous": "Anterior", + "lightbox.view_context": "Veure el context", "lists.account.add": "Afegir a la llista", "lists.account.remove": "Treure de la llista", "lists.delete": "Delete list", @@ -340,7 +342,6 @@ "status.reply": "Respondre", "status.replyAll": "Respondre al tema", "status.report": "Informar sobre @{name}", - "status.sensitive_toggle": "Clic per veure", "status.sensitive_warning": "Contingut sensible", "status.share": "Compartir", "status.show_less": "Mostra menys", diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 6169767dae..e76182bf4d 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -269,6 +269,7 @@ ca: created_msg: El bloqueig de domini ara s'està processant destroyed_msg: El bloqueig de domini s'ha desfet domain: Domini + existing_domain_block_html: Ja has imposat uns limits més estrictes a %{name}, l'hauries de desbloquejar-lo primer. new: create: Crea un bloqueig hint: El bloqueig de domini no impedirà la creació de nous comptes en la base de dades, però s'aplicaran de manera retroactiva mètodes de moderació específics sobre aquests comptes. @@ -655,7 +656,7 @@ ca: invalid_token: Els tokens de Keybase són hashs de signatures i han de tenir 66 caràcters hexadecimals verification_failed: Keybase no reconeix aquest token com a signatura del usuari de Keybase %{kb_username}. Si us plau prova des de Keybase. wrong_user: No es pot crear una prova per a %{proving} mentre es connectava com a %{current}. Inicia sessió com a %{proving} i prova de nou. - explanation_html: Aquí pots connectar criptogràficament les teves altres identitats com ara el teu perfil de Keybase. Això permet que altres persones t'envïin missatges xifrats i continguts de confiança que els hi enviess. + explanation_html: Aquí pots connectar criptogràficament les teves altres identitats com ara el teu perfil de Keybase. Això permet que altres persones t'envïin missatges xifrats i confiar en el contingut que els hi envies. i_am_html: Sóc %{username} a %{service}. identity: Identitat inactive: Inactiu @@ -675,7 +676,7 @@ ca: blocking: Llista de blocats domain_blocking: Llistat de dominis bloquejats following: Llista de seguits - muting: Llista d'apagats + muting: Llista de silenciats upload: Carregar in_memoriam_html: En Memòria. invites: @@ -778,7 +779,7 @@ ca: preferences: languages: Llengues other: Altre - publishing: Publicació + publishing: Publicant web: Web relationships: activity: Activitat del compte @@ -922,7 +923,7 @@ ca: sensitive_content: Contingut sensible terms: body_html: | -

Privacy Policy

+

Política de Privacitat

Quina informació recollim?

    From fbff73eccb56aac56535eb55743958424f56fd67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 7 May 2019 14:47:46 +0900 Subject: [PATCH 07/23] Bump redis from 4.1.0 to 4.1.1 (#10722) Bumps [redis](https://github.com/redis/redis-rb) from 4.1.0 to 4.1.1. - [Release notes](https://github.com/redis/redis-rb/releases) - [Changelog](https://github.com/redis/redis-rb/blob/master/CHANGELOG.md) - [Commits](https://github.com/redis/redis-rb/compare/v4.1.0...v4.1.1) Signed-off-by: dependabot[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index ec8bc18574..bfe8c558f3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -478,7 +478,7 @@ GEM link_header (~> 0.0, >= 0.0.8) rdf-normalize (0.3.3) rdf (>= 2.2, < 4.0) - redis (4.1.0) + redis (4.1.1) redis-actionpack (5.0.2) actionpack (>= 4.0, < 6) redis-rack (>= 1, < 3) From 5c82d660d11d38c2f13c6c8a4f1c60f62f6176cb Mon Sep 17 00:00:00 2001 From: nzws Date: Wed, 8 May 2019 06:53:58 +0900 Subject: [PATCH 08/23] Fix some colors of high contrast theme (#10711) * Fix "nothing here" text color of high contrast * Fix counter border color of high contrast --- app/javascript/styles/contrast/diff.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/javascript/styles/contrast/diff.scss b/app/javascript/styles/contrast/diff.scss index 8429103b8a..f78e605975 100644 --- a/app/javascript/styles/contrast/diff.scss +++ b/app/javascript/styles/contrast/diff.scss @@ -67,3 +67,11 @@ text-decoration: none; } } + +.nothing-here { + color: $darker-text-color; +} + +.public-layout .public-account-header__tabs__tabs .counter.active::after { + border-bottom: 4px solid $ui-highlight-color; +} From 09eea46631c99792e6e3b59ee20253827fd87ade Mon Sep 17 00:00:00 2001 From: Jeong Arm Date: Thu, 9 May 2019 01:01:33 +0900 Subject: [PATCH 09/23] Bring back crossed eye icon on gallery (#10715) --- .../features/account_gallery/components/media_item.js | 11 +++++++++++ app/javascript/styles/mastodon/components.scss | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/app/javascript/mastodon/features/account_gallery/components/media_item.js b/app/javascript/mastodon/features/account_gallery/components/media_item.js index f44e209398..2609b96ffc 100644 --- a/app/javascript/mastodon/features/account_gallery/components/media_item.js +++ b/app/javascript/mastodon/features/account_gallery/components/media_item.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import Icon from 'mastodon/components/icon'; import { autoPlayGif, displayMedia } from 'mastodon/initial_state'; import classNames from 'classnames'; import { decode } from 'blurhash'; @@ -91,6 +92,7 @@ export default class MediaItem extends ImmutablePureComponent { const title = status.get('spoiler_text') || attachment.get('description'); let thumbnail = ''; + let icon; if (attachment.get('type') === 'unknown') { // Skip @@ -132,11 +134,20 @@ export default class MediaItem extends ImmutablePureComponent { ); } + if (!visible) { + icon = ( + + + + ); + } + return ( ); diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index cf8fa9392b..0da3ed9096 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -4829,6 +4829,14 @@ a.status-card.compact:hover { border-radius: 4px; overflow: hidden; margin: 2px; + + &__icons { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 24px; + } } .notification__filter-bar, From ce8635605c3be41ef0a20ade0e7a89b170bf7f04 Mon Sep 17 00:00:00 2001 From: Jeong Arm Date: Fri, 10 May 2019 05:03:03 +0900 Subject: [PATCH 10/23] Record deleted(by mod) status to prevent re-appear (#10732) * Record deleted(by mod) status to prevent re-appear * Move to Tombstone * Add missing migration script --- app/models/form/status_batch.rb | 1 + app/models/tombstone.rb | 11 ++++++----- .../20190509164208_add_by_moderator_to_tombstone.rb | 5 +++++ db/schema.rb | 5 +++-- 4 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 db/migrate/20190509164208_add_by_moderator_to_tombstone.rb diff --git a/app/models/form/status_batch.rb b/app/models/form/status_batch.rb index 8987280675..933dfdaca1 100644 --- a/app/models/form/status_batch.rb +++ b/app/models/form/status_batch.rb @@ -35,6 +35,7 @@ class Form::StatusBatch def delete_statuses Status.where(id: status_ids).reorder(nil).find_each do |status| RemovalWorker.perform_async(status.id) + Tombstone.find_or_create_by(uri: status.uri, account: status.account, by_moderator: true) log_action :destroy, status end diff --git a/app/models/tombstone.rb b/app/models/tombstone.rb index 997bb65fd0..bf666c43ac 100644 --- a/app/models/tombstone.rb +++ b/app/models/tombstone.rb @@ -4,11 +4,12 @@ # # Table name: tombstones # -# id :bigint(8) not null, primary key -# account_id :bigint(8) -# uri :string not null -# created_at :datetime not null -# updated_at :datetime not null +# id :bigint(8) not null, primary key +# account_id :bigint(8) +# uri :string not null +# created_at :datetime not null +# updated_at :datetime not null +# by_moderator :boolean # class Tombstone < ApplicationRecord diff --git a/db/migrate/20190509164208_add_by_moderator_to_tombstone.rb b/db/migrate/20190509164208_add_by_moderator_to_tombstone.rb new file mode 100644 index 0000000000..80c2448428 --- /dev/null +++ b/db/migrate/20190509164208_add_by_moderator_to_tombstone.rb @@ -0,0 +1,5 @@ +class AddByModeratorToTombstone < ActiveRecord::Migration[5.2] + def change + add_column :tombstones, :by_moderator, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 8613539d64..4dcbea4e75 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_04_20_025523) do +ActiveRecord::Schema.define(version: 2019_05_09_164208) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -382,9 +382,9 @@ ActiveRecord::Schema.define(version: 2019_04_20_025523) do create_table "mutes", force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.boolean "hide_notifications", default: true, null: false t.bigint "account_id", null: false t.bigint "target_account_id", null: false - t.boolean "hide_notifications", default: true, null: false t.index ["account_id", "target_account_id"], name: "index_mutes_on_account_id_and_target_account_id", unique: true t.index ["target_account_id"], name: "index_mutes_on_target_account_id" end @@ -676,6 +676,7 @@ ActiveRecord::Schema.define(version: 2019_04_20_025523) do t.string "uri", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.boolean "by_moderator" t.index ["account_id"], name: "index_tombstones_on_account_id" t.index ["uri"], name: "index_tombstones_on_uri" end From 03801fcaa5f93e0c9da1a70caf596f66a632f335 Mon Sep 17 00:00:00 2001 From: Jeong Arm Date: Fri, 10 May 2019 05:03:21 +0900 Subject: [PATCH 11/23] Remove custom emojis on "tootctl domains purge" (#10721) * Remove custom emojis on domains purge * Change message "Removing" to "Removed" --- lib/mastodon/domains_cli.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/mastodon/domains_cli.rb b/lib/mastodon/domains_cli.rb index 303b8a94a0..b081581fe5 100644 --- a/lib/mastodon/domains_cli.rb +++ b/lib/mastodon/domains_cli.rb @@ -28,10 +28,15 @@ module Mastodon say('.', :green, false) end - DomainBlock.where(domain: domain).destroy_all + DomainBlock.where(domain: domain).destroy_all unless options[:dry_run] say say("Removed #{removed} accounts#{dry_run}", :green) + + custom_emojis = CustomEmoji.where(domain: domain) + custom_emojis_count = custom_emojis.count + custom_emojis.destroy_all unless options[:dry_run] + say("Removed #{custom_emojis_count} custom emojis", :green) end option :concurrency, type: :numeric, default: 50, aliases: [:c] From 0402c52f28b73824d7c81c702a16d39fd97808cf Mon Sep 17 00:00:00 2001 From: Maciek Baron Date: Thu, 9 May 2019 21:03:32 +0100 Subject: [PATCH 12/23] Improve poll link accessibility (#10720) * Add distinction between hover and active/focus states * Resolves #10198 --- app/javascript/styles/mastodon/polls.scss | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/javascript/styles/mastodon/polls.scss b/app/javascript/styles/mastodon/polls.scss index d8bc5473a7..37c454a783 100644 --- a/app/javascript/styles/mastodon/polls.scss +++ b/app/javascript/styles/mastodon/polls.scss @@ -114,11 +114,14 @@ text-decoration: underline; font-size: inherit; - &:hover, - &:focus, - &:active { + &:hover { text-decoration: none; } + + &:active, + &:focus { + background-color: rgba($dark-text-color, .1); + } } .button { From 26fc21c18844802652ff1f5910acaa91ebe19de4 Mon Sep 17 00:00:00 2001 From: ThibG Date: Thu, 9 May 2019 22:03:44 +0200 Subject: [PATCH 13/23] Add some caching for HTML versions of statuses pages (#10701) --- app/controllers/statuses_controller.rb | 5 ++++- app/controllers/stream_entries_controller.rb | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb index fc44d5fb1d..e60646ba33 100644 --- a/app/controllers/statuses_controller.rb +++ b/app/controllers/statuses_controller.rb @@ -27,7 +27,10 @@ class StatusesController < ApplicationController def show respond_to do |format| format.html do - mark_cacheable! unless user_signed_in? + unless user_signed_in? + skip_session! + expires_in 10.seconds, public: true + end @body_classes = 'with-modals' diff --git a/app/controllers/stream_entries_controller.rb b/app/controllers/stream_entries_controller.rb index 8568b151cf..b75cefa74c 100644 --- a/app/controllers/stream_entries_controller.rb +++ b/app/controllers/stream_entries_controller.rb @@ -15,6 +15,11 @@ class StreamEntriesController < ApplicationController def show respond_to do |format| format.html do + unless user_signed_in? + skip_session! + expires_in 5.minutes, public: true + end + redirect_to short_account_status_url(params[:account_username], @stream_entry.activity) if @type == 'status' end From 62f5235b6f906a3336292a1a3afa222084de9a97 Mon Sep 17 00:00:00 2001 From: ThibG Date: Thu, 9 May 2019 22:05:43 +0200 Subject: [PATCH 14/23] Prevent silenced local users from notifying remote users not following them (#10575) * Prevent silenced local users from notifying remote users not following them This is an attempt to extend the local restrictions of silenced users to the federation. * Add tests * Add tests for making sure private status don't get sent over OStatus --- app/lib/activitypub/tag_manager.rb | 20 ++++++++++-- spec/lib/activitypub/tag_manager_spec.rb | 32 +++++++++++++++++++ .../services/process_mentions_service_spec.rb | 27 ++++++++++++++-- 3 files changed, 74 insertions(+), 5 deletions(-) diff --git a/app/lib/activitypub/tag_manager.rb b/app/lib/activitypub/tag_manager.rb index 892bb9974a..595291342a 100644 --- a/app/lib/activitypub/tag_manager.rb +++ b/app/lib/activitypub/tag_manager.rb @@ -65,7 +65,14 @@ class ActivityPub::TagManager when 'unlisted', 'private' [account_followers_url(status.account)] when 'direct', 'limited' - status.active_mentions.map { |mention| uri_for(mention.account) } + if status.account.silenced? + # Only notify followers if the account is locally silenced + account_ids = status.active_mentions.pluck(:account_id) + to = status.account.followers.where(id: account_ids).map { |account| uri_for(account) } + to.concat(FollowRequest.where(target_account_id: status.account_id, account_id: account_ids).map { |request| uri_for(request.account) }) + else + status.active_mentions.map { |mention| uri_for(mention.account) } + end end end @@ -86,7 +93,16 @@ class ActivityPub::TagManager cc << COLLECTIONS[:public] end - cc.concat(status.active_mentions.map { |mention| uri_for(mention.account) }) unless status.direct_visibility? || status.limited_visibility? + unless status.direct_visibility? || status.limited_visibility? + if status.account.silenced? + # Only notify followers if the account is locally silenced + account_ids = status.active_mentions.pluck(:account_id) + cc.concat(status.account.followers.where(id: account_ids).map { |account| uri_for(account) }) + cc.concat(FollowRequest.where(target_account_id: status.account_id, account_id: account_ids).map { |request| uri_for(request.account) }) + else + cc.concat(status.active_mentions.map { |mention| uri_for(mention.account) }) + end + end cc end diff --git a/spec/lib/activitypub/tag_manager_spec.rb b/spec/lib/activitypub/tag_manager_spec.rb index 0d16652169..6d246629e7 100644 --- a/spec/lib/activitypub/tag_manager_spec.rb +++ b/spec/lib/activitypub/tag_manager_spec.rb @@ -41,6 +41,22 @@ RSpec.describe ActivityPub::TagManager do status.mentions.create(account: mentioned) expect(subject.to(status)).to eq [subject.uri_for(mentioned)] end + + it "returns URIs of mentions for direct silenced author's status only if they are followers or requesting to be" do + bob = Fabricate(:account, username: 'bob') + alice = Fabricate(:account, username: 'alice') + foo = Fabricate(:account) + author = Fabricate(:account, username: 'author', silenced: true) + status = Fabricate(:status, visibility: :direct, account: author) + bob.follow!(author) + FollowRequest.create!(account: foo, target_account: author) + status.mentions.create(account: alice) + status.mentions.create(account: bob) + status.mentions.create(account: foo) + expect(subject.to(status)).to include(subject.uri_for(bob)) + expect(subject.to(status)).to include(subject.uri_for(foo)) + expect(subject.to(status)).to_not include(subject.uri_for(alice)) + end end describe '#cc' do @@ -70,6 +86,22 @@ RSpec.describe ActivityPub::TagManager do status.mentions.create(account: mentioned) expect(subject.cc(status)).to include(subject.uri_for(mentioned)) end + + it "returns URIs of mentions for silenced author's non-direct status only if they are followers or requesting to be" do + bob = Fabricate(:account, username: 'bob') + alice = Fabricate(:account, username: 'alice') + foo = Fabricate(:account) + author = Fabricate(:account, username: 'author', silenced: true) + status = Fabricate(:status, visibility: :public, account: author) + bob.follow!(author) + FollowRequest.create!(account: foo, target_account: author) + status.mentions.create(account: alice) + status.mentions.create(account: bob) + status.mentions.create(account: foo) + expect(subject.cc(status)).to include(subject.uri_for(bob)) + expect(subject.cc(status)).to include(subject.uri_for(foo)) + expect(subject.cc(status)).to_not include(subject.uri_for(alice)) + end end describe '#local_uri?' do diff --git a/spec/services/process_mentions_service_spec.rb b/spec/services/process_mentions_service_spec.rb index 963924fa9c..8a6bb44aca 100644 --- a/spec/services/process_mentions_service_spec.rb +++ b/spec/services/process_mentions_service_spec.rb @@ -1,10 +1,11 @@ require 'rails_helper' RSpec.describe ProcessMentionsService, type: :service do - let(:account) { Fabricate(:account, username: 'alice') } - let(:status) { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct}") } + let(:account) { Fabricate(:account, username: 'alice') } + let(:visibility) { :public } + let(:status) { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct}", visibility: visibility) } - context 'OStatus' do + context 'OStatus with public toot' do let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') } subject { ProcessMentionsService.new } @@ -23,6 +24,26 @@ RSpec.describe ProcessMentionsService, type: :service do end end + context 'OStatus with private toot' do + let(:visibility) { :private } + let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') } + + subject { ProcessMentionsService.new } + + before do + stub_request(:post, remote_user.salmon_url) + subject.call(status) + end + + it 'does not create a mention' do + expect(remote_user.mentions.where(status: status).count).to eq 0 + end + + it 'does not post to remote user\'s Salmon end point' do + expect(a_request(:post, remote_user.salmon_url)).to_not have_been_made + end + end + context 'ActivityPub' do let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } From f2be71c2931e0d0b8f1ec05f50bd7d791c420c91 Mon Sep 17 00:00:00 2001 From: ThibG Date: Thu, 9 May 2019 22:10:27 +0200 Subject: [PATCH 15/23] Add emoji suggestions to CW and poll option fields (#10555) * Refactor selectComposeSuggestion so that different paths can be updated * Add suggestions in CW field * Add emoji suggestion to poll options * Attempt to fix CSS * Hide suggestions by default They will be enabled if the input has focus --- app/javascript/mastodon/actions/compose.js | 3 +- .../mastodon/components/autosuggest_input.js | 229 ++++++++++++++++++ .../components/autosuggest_textarea.js | 12 +- .../compose/components/compose_form.js | 28 ++- .../features/compose/components/poll_form.js | 34 ++- .../containers/compose_form_container.js | 4 +- .../compose/containers/poll_form_container.js | 19 ++ app/javascript/mastodon/reducers/compose.js | 14 +- .../styles/mastodon/components.scss | 1 + app/javascript/styles/mastodon/polls.scss | 8 +- 10 files changed, 328 insertions(+), 24 deletions(-) create mode 100644 app/javascript/mastodon/components/autosuggest_input.js diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index 0ee663766a..94062f2be8 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -383,7 +383,7 @@ export function readyComposeSuggestionsAccounts(token, accounts) { }; }; -export function selectComposeSuggestion(position, token, suggestion) { +export function selectComposeSuggestion(position, token, suggestion, path) { return (dispatch, getState) => { let completion, startPosition; @@ -405,6 +405,7 @@ export function selectComposeSuggestion(position, token, suggestion) { position: startPosition, token, completion, + path, }); }; }; diff --git a/app/javascript/mastodon/components/autosuggest_input.js b/app/javascript/mastodon/components/autosuggest_input.js new file mode 100644 index 0000000000..bb8ab60db5 --- /dev/null +++ b/app/javascript/mastodon/components/autosuggest_input.js @@ -0,0 +1,229 @@ +import React from 'react'; +import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container'; +import AutosuggestEmoji from './autosuggest_emoji'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import PropTypes from 'prop-types'; +import { isRtl } from '../rtl'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import classNames from 'classnames'; +import { List as ImmutableList } from 'immutable'; + +const textAtCursorMatchesToken = (str, caretPosition, searchTokens) => { + let word; + + let left = str.slice(0, caretPosition).search(/\S+$/); + let right = str.slice(caretPosition).search(/\s/); + + if (right < 0) { + word = str.slice(left); + } else { + word = str.slice(left, right + caretPosition); + } + + if (!word || word.trim().length < 3 || searchTokens.indexOf(word[0]) === -1) { + return [null, null]; + } + + word = word.trim().toLowerCase(); + + if (word.length > 0) { + return [left + 1, word]; + } else { + return [null, null]; + } +}; + +export default class AutosuggestInput extends ImmutablePureComponent { + + static propTypes = { + value: PropTypes.string, + suggestions: ImmutablePropTypes.list, + disabled: PropTypes.bool, + placeholder: PropTypes.string, + onSuggestionSelected: PropTypes.func.isRequired, + onSuggestionsClearRequested: PropTypes.func.isRequired, + onSuggestionsFetchRequested: PropTypes.func.isRequired, + onChange: PropTypes.func.isRequired, + onKeyUp: PropTypes.func, + onKeyDown: PropTypes.func, + autoFocus: PropTypes.bool, + className: PropTypes.string, + id: PropTypes.string, + searchTokens: PropTypes.list, + maxLength: PropTypes.number, + }; + + static defaultProps = { + autoFocus: true, + searchTokens: ImmutableList(['@', ':', '#']), + }; + + state = { + suggestionsHidden: true, + focused: false, + selectedSuggestion: 0, + lastToken: null, + tokenStart: 0, + }; + + onChange = (e) => { + const [ tokenStart, token ] = textAtCursorMatchesToken(e.target.value, e.target.selectionStart, this.props.searchTokens); + + if (token !== null && this.state.lastToken !== token) { + this.setState({ lastToken: token, selectedSuggestion: 0, tokenStart }); + this.props.onSuggestionsFetchRequested(token); + } else if (token === null) { + this.setState({ lastToken: null }); + this.props.onSuggestionsClearRequested(); + } + + this.props.onChange(e); + } + + onKeyDown = (e) => { + const { suggestions, disabled } = this.props; + const { selectedSuggestion, suggestionsHidden } = this.state; + + if (disabled) { + e.preventDefault(); + return; + } + + if (e.which === 229 || e.isComposing) { + // Ignore key events during text composition + // e.key may be a name of the physical key even in this case (e.x. Safari / Chrome on Mac) + return; + } + + switch(e.key) { + case 'Escape': + if (suggestions.size === 0 || suggestionsHidden) { + document.querySelector('.ui').parentElement.focus(); + } else { + e.preventDefault(); + this.setState({ suggestionsHidden: true }); + } + + break; + case 'ArrowDown': + if (suggestions.size > 0 && !suggestionsHidden) { + e.preventDefault(); + this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) }); + } + + break; + case 'ArrowUp': + if (suggestions.size > 0 && !suggestionsHidden) { + e.preventDefault(); + this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) }); + } + + break; + case 'Enter': + case 'Tab': + // Select suggestion + if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) { + e.preventDefault(); + e.stopPropagation(); + this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion)); + } + + break; + } + + if (e.defaultPrevented || !this.props.onKeyDown) { + return; + } + + this.props.onKeyDown(e); + } + + onBlur = () => { + this.setState({ suggestionsHidden: true, focused: false }); + } + + onFocus = () => { + this.setState({ focused: true }); + } + + onSuggestionClick = (e) => { + const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute('data-index')); + e.preventDefault(); + this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion); + this.input.focus(); + } + + componentWillReceiveProps (nextProps) { + if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) { + this.setState({ suggestionsHidden: false }); + } + } + + setInput = (c) => { + this.input = c; + } + + renderSuggestion = (suggestion, i) => { + const { selectedSuggestion } = this.state; + let inner, key; + + if (typeof suggestion === 'object') { + inner = ; + key = suggestion.id; + } else if (suggestion[0] === '#') { + inner = suggestion; + key = suggestion; + } else { + inner = ; + key = suggestion; + } + + return ( +
    + {inner} +
    + ); + } + + render () { + const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, className, id, maxLength } = this.props; + const { suggestionsHidden } = this.state; + const style = { direction: 'ltr' }; + + if (isRtl(value)) { + style.direction = 'rtl'; + } + + return ( +
    + + +
    + {suggestions.map(this.renderSuggestion)} +
    +
    + ); + } + +} diff --git a/app/javascript/mastodon/components/autosuggest_textarea.js b/app/javascript/mastodon/components/autosuggest_textarea.js index a4f5cf50c6..f3fb7fa8bf 100644 --- a/app/javascript/mastodon/components/autosuggest_textarea.js +++ b/app/javascript/mastodon/components/autosuggest_textarea.js @@ -55,7 +55,8 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { }; state = { - suggestionsHidden: false, + suggestionsHidden: true, + focused: false, selectedSuggestion: 0, lastToken: null, tokenStart: 0, @@ -134,7 +135,11 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { } onBlur = () => { - this.setState({ suggestionsHidden: true }); + this.setState({ suggestionsHidden: true, focused: false }); + } + + onFocus = () => { + this.setState({ focused: true }); } onSuggestionClick = (e) => { @@ -145,7 +150,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { } componentWillReceiveProps (nextProps) { - if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden) { + if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) { this.setState({ suggestionsHidden: false }); } } @@ -207,6 +212,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { onChange={this.onChange} onKeyDown={this.onKeyDown} onKeyUp={onKeyUp} + onFocus={this.onFocus} onBlur={this.onBlur} onPaste={this.onPaste} style={style} diff --git a/app/javascript/mastodon/features/compose/components/compose_form.js b/app/javascript/mastodon/features/compose/components/compose_form.js index 2b9da20d7f..cf82ef5a87 100644 --- a/app/javascript/mastodon/features/compose/components/compose_form.js +++ b/app/javascript/mastodon/features/compose/components/compose_form.js @@ -5,6 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import ReplyIndicatorContainer from '../containers/reply_indicator_container'; import AutosuggestTextarea from '../../../components/autosuggest_textarea'; +import AutosuggestInput from '../../../components/autosuggest_input'; import PollButtonContainer from '../containers/poll_button_container'; import UploadButtonContainer from '../containers/upload_button_container'; import { defineMessages, injectIntl } from 'react-intl'; @@ -102,7 +103,11 @@ class ComposeForm extends ImmutablePureComponent { } onSuggestionSelected = (tokenStart, token, value) => { - this.props.onSuggestionSelected(tokenStart, token, value); + this.props.onSuggestionSelected(tokenStart, token, value, ['text']); + } + + onSpoilerSuggestionSelected = (tokenStart, token, value) => { + this.props.onSuggestionSelected(tokenStart, token, value, ['spoiler_text']); } handleChangeSpoilerText = (e) => { @@ -135,7 +140,7 @@ class ComposeForm extends ImmutablePureComponent { this.autosuggestTextarea.textarea.focus(); } else if (this.props.spoiler !== prevProps.spoiler) { if (this.props.spoiler) { - this.spoilerText.focus(); + this.spoilerText.input.focus(); } else { this.autosuggestTextarea.textarea.focus(); } @@ -178,10 +183,21 @@ class ComposeForm extends ImmutablePureComponent {
    - +
    diff --git a/app/javascript/mastodon/features/compose/components/poll_form.js b/app/javascript/mastodon/features/compose/components/poll_form.js index 383e37eb65..211601d520 100644 --- a/app/javascript/mastodon/features/compose/components/poll_form.js +++ b/app/javascript/mastodon/features/compose/components/poll_form.js @@ -5,6 +5,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import IconButton from 'mastodon/components/icon_button'; import Icon from 'mastodon/components/icon'; +import AutosuggestInput from 'mastodon/components/autosuggest_input'; import classNames from 'classnames'; const messages = defineMessages({ @@ -27,6 +28,10 @@ class Option extends React.PureComponent { onChange: PropTypes.func.isRequired, onRemove: PropTypes.func.isRequired, onToggleMultiple: PropTypes.func.isRequired, + suggestions: ImmutablePropTypes.list, + onClearSuggestions: PropTypes.func.isRequired, + onFetchSuggestions: PropTypes.func.isRequired, + onSuggestionSelected: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, }; @@ -38,12 +43,25 @@ class Option extends React.PureComponent { this.props.onRemove(this.props.index); }; + handleToggleMultiple = e => { this.props.onToggleMultiple(); e.preventDefault(); e.stopPropagation(); }; + onSuggestionsClearRequested = () => { + this.props.onClearSuggestions(); + } + + onSuggestionsFetchRequested = (token) => { + this.props.onFetchSuggestions(token); + } + + onSuggestionSelected = (tokenStart, token, value) => { + this.props.onSuggestionSelected(tokenStart, token, value, ['poll', 'options', this.props.index]); + } + render () { const { isPollMultiple, title, index, intl } = this.props; @@ -57,12 +75,16 @@ class Option extends React.PureComponent { tabIndex='0' /> - @@ -87,6 +109,10 @@ class PollForm extends ImmutablePureComponent { onAddOption: PropTypes.func.isRequired, onRemoveOption: PropTypes.func.isRequired, onChangeSettings: PropTypes.func.isRequired, + suggestions: ImmutablePropTypes.list, + onClearSuggestions: PropTypes.func.isRequired, + onFetchSuggestions: PropTypes.func.isRequired, + onSuggestionSelected: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, }; @@ -103,7 +129,7 @@ class PollForm extends ImmutablePureComponent { }; render () { - const { options, expiresIn, isMultiple, onChangeOption, onRemoveOption, intl } = this.props; + const { options, expiresIn, isMultiple, onChangeOption, onRemoveOption, intl, ...other } = this.props; if (!options) { return null; @@ -112,7 +138,7 @@ class PollForm extends ImmutablePureComponent { return (
      - {options.map((title, i) =>
    diff --git a/app/javascript/mastodon/features/compose/containers/compose_form_container.js b/app/javascript/mastodon/features/compose/containers/compose_form_container.js index f9f1fba366..93a4683880 100644 --- a/app/javascript/mastodon/features/compose/containers/compose_form_container.js +++ b/app/javascript/mastodon/features/compose/containers/compose_form_container.js @@ -45,8 +45,8 @@ const mapDispatchToProps = (dispatch) => ({ dispatch(fetchComposeSuggestions(token)); }, - onSuggestionSelected (position, token, suggestion) { - dispatch(selectComposeSuggestion(position, token, suggestion)); + onSuggestionSelected (position, token, suggestion, path) { + dispatch(selectComposeSuggestion(position, token, suggestion, path)); }, onChangeSpoilerText (checked) { diff --git a/app/javascript/mastodon/features/compose/containers/poll_form_container.js b/app/javascript/mastodon/features/compose/containers/poll_form_container.js index da795a2912..1401371d0f 100644 --- a/app/javascript/mastodon/features/compose/containers/poll_form_container.js +++ b/app/javascript/mastodon/features/compose/containers/poll_form_container.js @@ -1,8 +1,14 @@ import { connect } from 'react-redux'; import PollForm from '../components/poll_form'; import { addPollOption, removePollOption, changePollOption, changePollSettings } from '../../../actions/compose'; +import { + clearComposeSuggestions, + fetchComposeSuggestions, + selectComposeSuggestion, +} from '../../../actions/compose'; const mapStateToProps = state => ({ + suggestions: state.getIn(['compose', 'suggestions']), options: state.getIn(['compose', 'poll', 'options']), expiresIn: state.getIn(['compose', 'poll', 'expires_in']), isMultiple: state.getIn(['compose', 'poll', 'multiple']), @@ -24,6 +30,19 @@ const mapDispatchToProps = dispatch => ({ onChangeSettings(expiresIn, isMultiple) { dispatch(changePollSettings(expiresIn, isMultiple)); }, + + onClearSuggestions () { + dispatch(clearComposeSuggestions()); + }, + + onFetchSuggestions (token) { + dispatch(fetchComposeSuggestions(token)); + }, + + onSuggestionSelected (position, token, accountId, path) { + dispatch(selectComposeSuggestion(position, token, accountId, path)); + }, + }); export default connect(mapStateToProps, mapDispatchToProps)(PollForm); diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index b45def281b..39cc5bd817 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -131,13 +131,15 @@ function removeMedia(state, mediaId) { }); }; -const insertSuggestion = (state, position, token, completion) => { +const insertSuggestion = (state, position, token, completion, path) => { return state.withMutations(map => { - map.update('text', oldText => `${oldText.slice(0, position)}${completion} ${oldText.slice(position + token.length)}`); + map.updateIn(path, oldText => `${oldText.slice(0, position)}${completion} ${oldText.slice(position + token.length)}`); map.set('suggestion_token', null); - map.update('suggestions', ImmutableList(), list => list.clear()); - map.set('focusDate', new Date()); - map.set('caretPosition', position + completion.length + 1); + map.set('suggestions', ImmutableList()); + if (path.length === 1 && path[0] === 'text') { + map.set('focusDate', new Date()); + map.set('caretPosition', position + completion.length + 1); + } map.set('idempotencyKey', uuid()); }); }; @@ -304,7 +306,7 @@ export default function compose(state = initialState, action) { case COMPOSE_SUGGESTIONS_READY: return state.set('suggestions', ImmutableList(action.accounts ? action.accounts.map(item => item.id) : action.emojis)).set('suggestion_token', action.token); case COMPOSE_SUGGESTION_SELECT: - return insertSuggestion(state, action.position, action.token, action.completion); + return insertSuggestion(state, action.position, action.token, action.completion, action.path); case COMPOSE_SUGGESTION_TAGS_UPDATE: return updateSuggestionTags(state, action.token); case COMPOSE_TAG_HISTORY_UPDATE: diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 0da3ed9096..e8c5f70f55 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -319,6 +319,7 @@ } .autosuggest-textarea, + .autosuggest-input, .spoiler-input { position: relative; } diff --git a/app/javascript/styles/mastodon/polls.scss b/app/javascript/styles/mastodon/polls.scss index 37c454a783..0d55afda40 100644 --- a/app/javascript/styles/mastodon/polls.scss +++ b/app/javascript/styles/mastodon/polls.scss @@ -37,11 +37,14 @@ display: none; } + .autossugest-input { + flex: 1 1 auto; + } + input[type=text] { display: block; box-sizing: border-box; - flex: 1 1 auto; - width: 20px; + width: 100%; font-size: 14px; color: $inverted-text-color; display: block; @@ -64,6 +67,7 @@ &.editable { display: flex; align-items: center; + overflow: visible; } } From fe8a8f779e36e25286b6a7ddc7bcd08e2a4e2890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Reeves?= Date: Thu, 9 May 2019 22:39:27 +0200 Subject: [PATCH 16/23] Add confirm modal for unboosting toots (#10287) [#3815] Display the boost modal also when unboosting toots. --- .../mastodon/containers/status_container.js | 18 +++++++++--------- .../features/ui/components/boost_modal.js | 4 +++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/javascript/mastodon/containers/status_container.js b/app/javascript/mastodon/containers/status_container.js index 0fce674e20..86324b8468 100644 --- a/app/javascript/mastodon/containers/status_container.js +++ b/app/javascript/mastodon/containers/status_container.js @@ -69,18 +69,18 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ }, onModalReblog (status) { - dispatch(reblog(status)); - }, - - onReblog (status, e) { if (status.get('reblogged')) { dispatch(unreblog(status)); } else { - if (e.shiftKey || !boostModal) { - this.onModalReblog(status); - } else { - dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog })); - } + dispatch(reblog(status)); + } + }, + + onReblog (status, e) { + if (e.shiftKey || !boostModal) { + this.onModalReblog(status); + } else { + dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog })); } }, diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.js b/app/javascript/mastodon/features/ui/components/boost_modal.js index 920e93d404..4c39a60e79 100644 --- a/app/javascript/mastodon/features/ui/components/boost_modal.js +++ b/app/javascript/mastodon/features/ui/components/boost_modal.js @@ -11,6 +11,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import Icon from 'mastodon/components/icon'; const messages = defineMessages({ + cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' }, reblog: { id: 'status.reblog', defaultMessage: 'Boost' }, }); @@ -51,6 +52,7 @@ class BoostModal extends ImmutablePureComponent { render () { const { status, intl } = this.props; + const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog; return (
    @@ -76,7 +78,7 @@ class BoostModal extends ImmutablePureComponent {
    Shift + }} />
    -
    ); From a3c7dd92f37ad2767027322b098656f47ccddecc Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 9 May 2019 22:41:27 +0200 Subject: [PATCH 17/23] Add ES_PREFIX in .env.production.sample (#10087) --- .env.production.sample | 1 + 1 file changed, 1 insertion(+) diff --git a/.env.production.sample b/.env.production.sample index d1164efdc0..d66b050509 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -10,6 +10,7 @@ DB_NAME=postgres DB_PASS= DB_PORT=5432 # Optional ElasticSearch configuration +# You may also set ES_PREFIX to share the same cluster between multiple Mastodon servers (falls back to REDIS_NAMESPACE if not set) # ES_ENABLED=true # ES_HOST=es # ES_PORT=9200 From 9d4e9015a77a8f1dab1edd9a04cca1f7fc876645 Mon Sep 17 00:00:00 2001 From: manuelviens Date: Thu, 9 May 2019 17:15:39 -0400 Subject: [PATCH 18/23] Update fr.yml (#10727) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update fr.yml Added missing lines * Update fr.yml Application des modifications de ThibG * Update fr.yml Modifications proposées par ThibG --- config/locales/fr.yml | 123 +++++++++++++++++++++++++++++++++--------- 1 file changed, 99 insertions(+), 24 deletions(-) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index d588b239ff..b969fda083 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -4,17 +4,25 @@ fr: about_hashtag_html: Figurent ci-dessous les pouets tagués avec #%{hashtag}. Vous pouvez interagir avec eux si vous avez un compte n’importe où dans le Fediverse. about_mastodon_html: Mastodon est un réseau social utilisant des formats ouverts et des logiciels libres. Comme le courriel, il est décentralisé. about_this: À propos + active_count_after: actif·ve·s + active_footnote: Utilisateur·rice·s actif·ve·s mensuels (MAU) administered_by: 'Administrée par :' api: API apps: Applications mobiles + apps_platforms: Utilisez Mastodon depuis iOS, Android et d’autres plates-formes + browse_directory: Parcourir l’annuaire des profils et filtrer par centres d’intérêt + browse_public_posts: Parcourir un flux en direct de messages publics sur Mastodon contact: Contact contact_missing: Manquant contact_unavailable: Non disponible + discover_users: Découvrez des utilisateur·rice·s documentation: Documentation extended_description_html: |

    Un bon endroit pour les règles

    La description étendue n’a pas été remplie.

    + federation_hint_html: Avec un compte sur %{instance}, vous pourrez suivre les gens sur n’importe quel serveur Mastodon et au-delà. generic_description: "%{domain} est seulement un serveur du réseau" + get_apps: Essayez une application mobile hosted_on: Serveur Mastodon hébergée par %{domain} learn_more: En savoir plus privacy_policy: Politique de vie privée @@ -23,7 +31,8 @@ fr: one: Statut other: Statuts status_count_before: Ayant publié - terms: Conditions d'utilisation + tagline: Suivez vos ami·e·s et découvrez en de nouveaux·elles + terms: Conditions d’utilisation user_count_after: one: utilisateur other: utilisateurs @@ -113,15 +122,18 @@ fr: moderation: active: Actif all: Tous + pending: En cours de traitement silenced: Masqués suspended: Suspendus title: Modération moderation_notes: Notes de modération most_recent_activity: Dernière activité most_recent_ip: Adresse IP la plus récente + no_account_selected: Aucun compte n’a été modifié, car aucun n’a été sélectionné no_limits_imposed: Aucune limite imposée not_subscribed: Non abonné outbox_url: URL de sortie + pending: En attente d’approbation perform_full_suspension: Suspendre profile_url: URL du profil promote: Promouvoir @@ -129,8 +141,10 @@ fr: public: Publique push_subscription_expires: Expiration de l’abonnement PuSH redownload: Rafraîchir le profil + reject: Rejeter + reject_all: Tout rejeter remove_avatar: Supprimer l’avatar - remove_header: Supprimer l'entête + remove_header: Supprimer l’entête resend_confirmation: already_confirmed: Cet·te utilisateur·ice est déjà confirmé·e send: Renvoyer un courriel de confirmation @@ -149,7 +163,7 @@ fr: shared_inbox_url: URL de la boite de réception partagée show: created_reports: Signalements faits - targeted_reports: Signalés par d'autres + targeted_reports: Signalés par d’autres silence: Masquer silenced: Silencié statuses: Statuts @@ -173,7 +187,7 @@ fr: create_domain_block: "%{name} a bloqué le domaine %{target}" create_email_domain_block: "%{name} a mis le domaine du courriel %{target} sur liste noire" demote_user: "%{name} a rétrogradé l’utilisateur·ice %{target}" - destroy_custom_emoji: "%{name} a détruit l'émoticône %{target}" + destroy_custom_emoji: "%{name} a détruit l’émoticône %{target}" destroy_domain_block: "%{name} a débloqué le domaine %{target}" destroy_email_domain_block: "%{name} a mis le domaine du courriel %{target} sur liste blanche" destroy_status: "%{name} a enlevé le statut de %{target}" @@ -230,6 +244,7 @@ fr: feature_profile_directory: Annuaire des profils feature_registrations: Inscriptions feature_relay: Relais de fédération + feature_timeline_preview: Aperçu du fil public features: Fonctionnalités hidden_service: Fédération avec des services cachés open_reports: signalements non résolus @@ -249,6 +264,7 @@ fr: created_msg: Le blocage de domaine est désormais activé destroyed_msg: Le blocage de domaine a été désactivé domain: Domaine + existing_domain_block_html: Vous avez déjà imposé des limites plus strictes à %{name}, vous devez d’abord le débloquer. new: create: Créer le blocage hint: Le blocage de domaine n’empêchera pas la création de comptes dans la base de données, mais il appliquera automatiquement et rétrospectivement des méthodes de modération spécifiques sur ces comptes. @@ -314,6 +330,8 @@ fr: expired: Expiré title: Filtre title: Invitations + pending_accounts: + title: Comptes en attente (%{count}) relays: add_new: Ajouter un nouveau relais delete: Effacer @@ -324,7 +342,7 @@ fr: enable_hint: Une fois activé, votre serveur souscrira à tous les pouets publics présents sur ce relais et y enverra ses propres pouets publics. enabled: Activé inbox_url: URL de relais - pending: En attente de l'approbation du relai + pending: En attente de l’approbation du relai save_and_enable: Sauvegarder et activer setup: Paramétrer une connexion de relais status: Statut @@ -373,13 +391,13 @@ fr: email: Entrez une adresse courriel publique username: Entrez un nom d’utilisateur⋅ice custom_css: - desc_html: Modifier l'apparence avec une CSS chargée sur chaque page + desc_html: Modifier l’apparence avec une CSS chargée sur chaque page title: CSS personnalisé hero: desc_html: Affichée sur la page d’accueil. Au moins 600x100px recommandé. Lorsqu’elle n’est pas définie, se rabat sur la vignette du serveur title: Image d’en-tête mascot: - desc_html: Affiché sur plusieurs pages. Au moins 293×205px recommandé. Lorsqu'il n'est pas défini, retombe à la mascotte par défaut + desc_html: Affiché sur plusieurs pages. Au moins 293×205px recommandé. Lorsqu’il n’est pas défini, retombe à la mascotte par défaut title: Image de la mascotte peers_api_enabled: desc_html: Noms des domaines que ce serveur a découvert dans le fediverse @@ -388,8 +406,8 @@ fr: desc_html: Les liens de prévisualisation sur les autres sites web afficheront une vignette même si le média est sensible title: Afficher les médias sensibles dans les prévisualisations OpenGraph profile_directory: - desc_html: Permettre aux utilisateurs d'être découverts - title: Activer l'annuaire des profils + desc_html: Permettre aux utilisateurs d’être découverts + title: Activer l’annuaire des profils registrations: closed_message: desc_html: Affiché sur la page d’accueil lorsque les inscriptions sont fermées
    Vous pouvez utiliser des balises HTML @@ -400,6 +418,12 @@ fr: min_invite_role: disabled: Personne title: Autoriser les invitations par + registrations_mode: + modes: + approved: Approbation requise pour s’inscrire + none: Personne ne peut s’inscrire + open: N’importe qui peut s’inscrire + title: Mode d’enregistrement show_known_fediverse_at_about_page: desc_html: Lorsque l’option est activée, les pouets provenant de toutes les serveurs connues sont affichés dans la prévisualisation. Sinon, seuls les pouets locaux sont affichés. title: Afficher le fediverse connu dans la prévisualisation du fil @@ -410,7 +434,7 @@ fr: desc_html: Paragraphe introductif sur la page d’accueil. Décrivez ce qui rend spécifique ce serveur Mastodon et toute autre chose importante. Vous pouvez utiliser des balises HTML, en particulier <a> et <em>. title: Description du serveur site_description_extended: - desc_html: L'endroit idéal pour afficher votre code de conduite, les règles, les guides et autres choses qui rendent votre serveur différent. Vous pouvez utiliser des balises HTML + desc_html: L’endroit idéal pour afficher votre code de conduite, les règles, les guides et autres choses qui rendent votre serveur différent. Vous pouvez utiliser des balises HTML title: Description étendue du serveur site_short_description: desc_html: Affichée dans la barre latérale et dans les méta-tags. Décrivez ce qui rend spécifique ce serveur Mastodon en un seul paragraphe. Si laissée vide, la description du serveur sera affiché par défaut. @@ -449,19 +473,22 @@ fr: tags: accounts: Comptes hidden: Masqué - hide: Masquer dans l'annuaire + hide: Masquer dans l’annuaire name: Hashtag title: Hashtags - unhide: Afficher dans l'annuaire + unhide: Afficher dans l’annuaire visible: Visible title: Administration warning_presets: add_new: Ajouter un nouveau delete: Effacer edit: Éditer - edit_preset: Éditer la présélection d'attention - title: Gérer les présélections d'attention + edit_preset: Éditer la présélection d’avertissement + title: Gérer les présélections d’avertissement admin_mailer: + new_pending_account: + body: Les détails du nouveau compte se trouvent ci-dessous. Vous pouvez approuver ou rejeter cette demande. + subject: Nouveau compte à examiner sur %{instance} (%{username}) new_report: body: "%{reporter} a signalé %{target}" body_remote: Quelqu’un de %{domain} a signalé %{target} @@ -482,7 +509,9 @@ fr: warning: Soyez prudent⋅e avec ces données. Ne les partagez pas ! your_token: Votre jeton d’accès auth: + apply_for_account: Demander une invitation change_password: Mot de passe + checkbox_agreement_html: J’accepte les règles du serveur et les conditions de service confirm_email: Confirmer mon adresse mail delete_account: Supprimer le compte delete_account_html: Si vous désirez supprimer votre compte, vous pouvez cliquer ici. Il vous sera demandé de confirmer cette action. @@ -498,10 +527,12 @@ fr: cas: CAS saml: SAML register: S’inscrire + registration_closed: "%{instance} n’accepte pas de nouveaux membres" resend_confirmation: Envoyer à nouveau les consignes de confirmation reset_password: Réinitialiser le mot de passe security: Sécurité set_new_password: Définir le nouveau mot de passe + trouble_logging_in: Vous avez un problème pour vous connecter ? authorize_follow: already_following: Vous suivez déjà ce compte error: Malheureusement, il y a eu une erreur en cherchant les détails du compte distant @@ -537,11 +568,11 @@ fr: warning_title: Disponibilité du contenu disséminé directories: directory: Annuaire des profils - enabled: Vous êtes actuellement listé dans l'annuaire. - enabled_but_waiting: Vous avez choisi d'être listé dans l'annuaire, mais vous n'avez pas encore le nombre minimum de suiveurs (%{min_followers}) pour y être inscrit. - explanation: Découvrir des utilisateurs en se basant sur leurs centres d'intérêt + enabled: Vous êtes actuellement listé dans l’annuaire. + enabled_but_waiting: Vous avez choisi d’être listé dans l’annuaire, mais vous n’avez pas encore le nombre minimum de suiveurs (%{min_followers}) pour y être inscrit. + explanation: Découvrir des utilisateurs en se basant sur leurs centres d’intérêt explore_mastodon: Explorer %{title} - how_to_enable: Vous n'êtes pas encore inscrit dans l'annuaire. Vous pouvez vous inscrire ci-dessous. Utilisez des hashtags dans votre texte biographique pour être listé sous des hashtags spécifiques ! + how_to_enable: Vous n’êtes pas encore inscrit dans l’annuaire. Vous pouvez vous inscrire ci-dessous. Utilisez des hashtags dans votre texte biographique pour être listé sous des hashtags spécifiques ! people: one: "%{count} personne" other: "%{count} personne" @@ -557,6 +588,9 @@ fr: content: Nous sommes désolé·e·s, mais quelque chose s’est mal passé de notre côté. title: Cette page n’est pas correcte noscript_html: Pour utiliser Mastodon, veuillez activer JavaScript. Sinon, essayez l’une des applications natives pour Mastodon pour votre plate-forme. + existing_username_validator: + not_found: n’a pas trouvé d’utilisateur·rice local·e avec ce nom + not_found_multiple: n’a pas trouvé %{usernames} exports: archive_takeout: date: Date @@ -597,19 +631,41 @@ fr: more: Davantage… resources: Ressources generic: + all: Tous changes_saved_msg: Les modifications ont été enregistrées avec succès ! copy: Copier + order_by: Classer par save_changes: Enregistrer les modifications validation_errors: one: Quelque chose ne va pas ! Vérifiez l’erreur ci-dessous other: Certaines choses ne vont pas ! Vérifiez les %{count} erreurs ci-dessous + html_validator: + invalid_markup: 'contient un balisage HTML invalide: %{error}' + identity_proofs: + active: Actif + authorize: Oui, autoriser + authorize_connection_prompt: Autoriser cette connexion chiffrée ? + errors: + failed: La connexion chiffrée a échoué. Veuillez réessayer à partir de %{provider}. + keybase: + invalid_token: Les jetons Keybase sont des hachages de signatures et doivent comporter 66 caractères hexadécimaux + verification_failed: Keybase ne reconnaît pas ce jeton comme une signature de l’utilisateur Keybase %{kb_username}. Veuillez réessayer à partir de Keybase. + wrong_user: Impossible de créer une preuve pour %{proving} lorsque vous êtes connecté en tant que %{current}. Connectez-vous en tant que %{proving} et réessayez. + explanation_html: Ici, vous pouvez connecter de manière chiffrée vos autres identités, par exemple un profil Keybase. Cela permet à d’autres personnes de vous envoyer des messages chiffrés et de faire confiance au contenu que vous leur envoyez. + i_am_html: Je suis %{username} sur %{service}. + identity: Identité + inactive: Inactif + publicize_checkbox: 'Et le poueter:' + publicize_toot: 'C’est prouvé ! Je suis %{username} sur %{service}: %{url}' + status: Statut de vérification + view_proof: Voir la preuve imports: modes: merge: Fusionner merge_long: Garder les enregistrements existants et ajouter les nouveaux overwrite: Réécrire overwrite_long: Remplacer les enregistrements actuels par les nouveaux - preface: Vous pouvez importer certaines données que vous avez exporté d'un autre serveur, comme une liste des personnes que vous suivez ou bloquez sur votre compte. + preface: Vous pouvez importer certaines données que vous avez exporté d’un autre serveur, comme une liste des personnes que vous suivez ou bloquez sur votre compte. success: Vos données ont été importées avec succès et seront traitées en temps et en heure types: blocking: Liste d’utilisateur⋅ice⋅s bloqué⋅e⋅s @@ -713,13 +769,26 @@ fr: duration_too_short: est trop tôt expired: Ce sondage est déjà terminé over_character_limit: ne peuvent être plus long que %{max} caractères chacun - too_few_options: doit avoir plus qu'une proposition + too_few_options: doit avoir plus qu’une proposition too_many_options: ne peut contenir plus que %{max} propositions preferences: languages: Langues other: Autre publishing: Publication web: Web + relationships: + activity: Activité du compte + dormant: Dormant + last_active: Dernière activité + most_recent: Plus récent + moved: Déménagé + mutual: Mutuel + primary: Primaire + relationship: Relation + remove_selected_domains: Supprimer tous les abonné·e·s des domaines sélectionnés + remove_selected_followers: Supprimer les abonné·e·s sélectionnés + remove_selected_follows: Cesser de suivre les utilisateur·rice·s sélectionné·e·s + status: Statut du compte remote_follow: acct: Entrez l’adresse profil@serveur depuis laquelle vous voulez vous abonner missing_resource: L’URL de redirection n’a pas pu être trouvée @@ -729,7 +798,7 @@ fr: reason_html: "Pourquoi cette étape est-elle nécessaire? %{instance} pourrait ne pas être le serveur où vous vous êtes inscrit, et nous devons donc vous rediriger vers votre serveur de base en premier." remote_interaction: favourite: - proceed: Confirmer l'ajout aux favoris + proceed: Confirmer l’ajout aux favoris prompt: 'Vous souhaitez mettre ce pouet en favori :' reblog: proceed: Confirmer le repartage @@ -787,6 +856,9 @@ fr: revoke_success: Session révoquée avec succès title: Sessions settings: + account: Compte + account_settings: Paramètres du compte + appearance: Apparence authorized_apps: Applications autorisées back: Retour vers Mastodon delete: Suppression de compte @@ -794,10 +866,13 @@ fr: edit_profile: Modifier le profil export: Export de données featured_tags: Hashtags mis en avant + identity_proofs: Preuves d’identité import: Import de données migrate: Migration de compte notifications: Notifications preferences: Préférences + profile: Profil + relationships: Abonnements et abonné·e·s two_factor_authentication: Identification à deux facteurs statuses: attached: @@ -954,8 +1029,8 @@ fr: title: Récupération de l’archive warning: explanation: - disable: Lorsque votre compte est gelé, les données de votre compte demeurent intactes, mais vous ne pouvez effectuer aucune action jusqu'à ce qu'il soit débloqué. - silence: Lorsque votre compte est limité, seulement les utilisateurs qui vous suivent déjà verront vos pouets sur ce serveur, et vous pourriez être exclu de plusieurs listes publiques. Néanmoins, d'autres utilisateurs peuvent vous suivre manuellement. + disable: Lorsque votre compte est gelé, les données de votre compte demeurent intactes, mais vous ne pouvez effectuer aucune action jusqu’à ce qu’il soit débloqué. + silence: Lorsque votre compte est limité, seulement les utilisateurs qui vous suivent déjà verront vos pouets sur ce serveur, et vous pourriez être exclu de plusieurs listes publiques. Néanmoins, d’autres utilisateurs peuvent vous suivre manuellement. suspend: Votre compte a été suspendu, et tous vos pouets et vos fichiers multimédia téléversés ont été supprimés irréversiblement de ce serveur, et des serveurs où vous aviez des abonné⋅e⋅s. review_server_policies: Passer en revue les politiques du serveur subject: @@ -993,5 +1068,5 @@ fr: seamless_external_login: Vous êtes connecté via un service externe, donc les paramètres concernant le mot de passe et le courriel ne sont pas disponibles. signed_in_as: 'Connecté·e en tant que :' verification: - explanation_html: 'Vous pouvez vérifier vous-même que vous êtes le propriétaire des liens dans les métadonnées de votre profil. Pour cela, le site Web lié doit contenir un lien vers votre profil Mastodon. Le lien de retour doitavoir un attribut rel="me". Le contenu textuel du lien n''a pas d''importance. En voici un exemple :' + explanation_html: 'Vous pouvez vérifier vous-même que vous êtes le propriétaire des liens dans les métadonnées de votre profil. Pour cela, le site Web lié doit contenir un lien vers votre profil Mastodon. Le lien de retour doitavoir un attribut rel="me". Le contenu textuel du lien n’a pas d’importance. En voici un exemple :' verification: Vérification From 9962174a1f57dedb470346fdc9e343ce5de088a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20=C4=BDach?= Date: Thu, 9 May 2019 23:16:05 +0200 Subject: [PATCH 19/23] Add strings for Slovak (#10734) * Add strings for Slovak * Update sk.yml --- config/locales/sk.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/config/locales/sk.yml b/config/locales/sk.yml index d859d16b1e..51795849c0 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -115,7 +115,7 @@ sk: followers: Sledujúci followers_url: URL adresa sledujúcich follows: Sledovania - header: Hlavička + header: Záhlavie inbox_url: URL adresa prijatých správ invited_by: Pozvaný/á užívateľom ip: IP adresa @@ -138,6 +138,7 @@ sk: moderation_notes: Moderátorské poznámky most_recent_activity: Posledná aktivita most_recent_ip: Posledná IP adresa + no_account_selected: Nedošlo k žiadnému pozmeneniu účtov, keďže žiadne neboli vybrané no_limits_imposed: Nie sú stanovené žiadné obmedzenia not_subscribed: Neodoberá outbox_url: URL poslaných @@ -152,7 +153,7 @@ sk: reject: Zamietni reject_all: Zamietni všetky remove_avatar: Vymaž avatar - remove_header: Vymaž hlavičku + remove_header: Vymaž záhlavie resend_confirmation: already_confirmed: Tento užívateľ je už potvrdený send: Odošli potvrdzovací email znovu @@ -319,7 +320,7 @@ sk: by_domain: Doména delivery_available: Je v dosahu doručovania known_accounts: - few: "%{count} známe účty" + few: "%{count} známych účtov" one: "%{count} známy účet" other: "%{count} známe účty" moderation: @@ -340,18 +341,20 @@ sk: expired: Vypršalo title: Filtruj title: Pozvánky + pending_accounts: + title: Čakajúcich účtov (%{count}) relays: add_new: Pridaj nový federovací mostík delete: Vymaž - description_html: "Federovací mostík je prechodný server ktorý obmieňa veľké množstvá verejných príspevkov medzi tými servermi ktoré na od neho odoberajú, aj doňho prispievajú. Môže to pomôcť malým a stredným instanciám objavovať federovaný obsah, čo inak vyžaduje aby miestni užívatelia ručne následovali iných ľudí zo vzdialených instancií." - disable: Pozastav - disabled: Zastavené + description_html: "Federovací mostík je prechodný server, ktorý obmieňa veľké množstvá verejných príspevkov medzi tými servermi ktoré na od neho odoberajú, aj doňho prispievajú. Môže to pomôcť malým a stredným instanciám objavovať federovaný obsah, čo inak vyžaduje aby miestni užívatelia ručne následovali iných ľudí zo vzdialených instancií." + disable: Vypni + disabled: Vypnutý enable: Povoľ enable_hint: Ak povolíš, tvoj server bude odoberať všetky verejné príspevky z tohto mostu, a začne posielať verejné príspevky tvojho servera na tento most. enabled: Povolené inbox_url: URL adresa mostu - pending: Čakám na povolenie od prechodného mostu - save_and_enable: Uložiť a povoliť + pending: Čaká sa na povolenie od prechodného mostu + save_and_enable: Ulož a povoľ setup: Nastav prepojenie s mostom status: Stav title: Mosty @@ -390,7 +393,7 @@ sk: updated_at: Aktualizované settings: activity_api_enabled: - desc_html: Sčítanie lokálne publikovaných príspevkov, aktívnych užívateľov, a nových registrácii, v týždenných intervaloch + desc_html: Sčítanie miestne uverejnených príspevkov, aktívnych užívateľov, a nových registrácii, v týždenných intervaloch title: Vydať hromadné štatistiky o užívateľskej aktivite bootstrap_timeline_accounts: desc_html: Ak je prezývok viacero, každú oddeľte čiarkou. Možno zadať iba miestne, odomknuté účty. Pokiaľ necháte prázdne, je to pre všetkých miestnych administrátorov. From 780d99c204df824fe959a3db00999f973a29c351 Mon Sep 17 00:00:00 2001 From: manuelviens Date: Thu, 9 May 2019 17:16:24 -0400 Subject: [PATCH 20/23] Update simple_form.fr.yml (#10726) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Minor modif and add Modified '' by ’ and added invite_request * Update simple_form.fr.yml Modifications suggérées par ThibG * Update simple_form.fr.yml Remplacement des ' par des ’. * Update simple_form.fr.yml Ajout de deux petits espaces devant sessions: --- config/locales/simple_form.fr.yml | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/config/locales/simple_form.fr.yml b/config/locales/simple_form.fr.yml index 0469ebe064..98c802abb2 100644 --- a/config/locales/simple_form.fr.yml +++ b/config/locales/simple_form.fr.yml @@ -5,8 +5,8 @@ fr: account_warning_preset: text: Vous pouvez utiliser la syntaxe des pouets, comme les URLs, les hashtags et les mentions admin_account_action: - send_email_notification: L'utilisateur recevra une explication de ce qu'il s'est passé avec son compte - text_html: Optionnel. Vous pouvez utilisez la syntaxe des pouets. Vous pouvez ajouter des présélections d'attention pour économiser du temps + send_email_notification: L’utilisateur recevra une explication de ce qu’il s’est passé avec son compte + text_html: Optionnel. Vous pouvez utilisez la syntaxe des pouets. Vous pouvez ajouter des présélections d’attention pour économiser du temps type_html: Choisir que faire avec %{acct} warning_preset_id: Optionnel. Vous pouvez toujours ajouter un texte personnalisé à la fin de la présélection defaults: @@ -15,7 +15,7 @@ fr: bot: Ce compte exécute principalement des actions automatisées et pourrait ne pas être surveillé context: Un ou plusieurs contextes où le filtre devrait s’appliquer digest: Uniquement envoyé après une longue période d’inactivité et uniquement si vous avez reçu des messages personnels pendant votre absence - discoverable_html: L'annuaire permet aux gens de trouver des comptes en se basant sur les intérêts et les activités. Nécessite au moins %{min_followers} abonnés + discoverable_html: L’annuaire permet aux gens de trouver des comptes en se basant sur les intérêts et les activités. Nécessite au moins %{min_followers} abonnés email: Vous recevrez un courriel de confirmation fields: Vous pouvez avoir jusqu’à 4 éléments affichés en tant que tableau sur votre profil header: Au format PNG, GIF ou JPG. %{size} maximum. Sera réduit à %{dimensions}px @@ -26,21 +26,23 @@ fr: password: Utilisez au moins 8 caractères phrase: Sera trouvé sans que la case ou l’avertissement de contenu du pouet soit pris en compte scopes: À quelles APIs l’application sera autorisée à accéder. Si vous sélectionnez un périmètre de haut-niveau, vous n’avez pas besoin de sélectionner les individuels. - setting_aggregate_reblogs: Ne pas afficher de nouveaux repartagés pour les pouets qui ont été récemment repartagés (n'affecte que les repartagés nouvellement reçus) + setting_aggregate_reblogs: Ne pas afficher de nouveaux repartagés pour les pouets qui ont été récemment repartagés (n’affecte que les repartagés nouvellement reçus) setting_default_language: La langue de vos pouets peut être détectée automatiquement, mais ça n’est pas toujours pertinent setting_display_media_default: Masquer les supports marqués comme sensibles setting_display_media_hide_all: Toujours masquer tous les médias setting_display_media_show_all: Toujours afficher les médias marqués comme sensibles setting_hide_network: Ceux que vous suivez et ceux qui vous suivent ne seront pas affichés sur votre profil setting_noindex: Affecte votre profil public ainsi que vos statuts - setting_show_application: Le nom de l'application que vous utilisez afin d'envoyer des pouets sera affiché dans la vue détaillée de ceux-ci + setting_show_application: Le nom de l’application que vous utilisez afin d’envoyer des pouets sera affiché dans la vue détaillée de ceux-ci setting_theme: Affecte l’apparence de Mastodon quand vous êtes connecté·e depuis n’importe quel appareil. username: Votre nom d’utilisateur sera unique sur %{domain} whole_word: Lorsque le mot-clef ou la phrase-clef est uniquement alphanumérique, ça sera uniquement appliqué s’il correspond au mot entier featured_tag: - name: 'Vous pourriez utiliser l''un d''entre eux :' + name: 'Vous pourriez vouloir utiliser l’un d’entre eux :' imports: data: Un fichier CSV généré par un autre serveur de Mastodon + invite_request: + text: Cela nous aidera à considérer votre demande sessions: otp: 'Entrez le code d’authentification à deux facteurs généré par l’application de votre téléphone ou utilisez un de vos codes de récupération :' user: @@ -53,7 +55,7 @@ fr: account_warning_preset: text: Texte de présélection admin_account_action: - send_email_notification: Notifier l'utilisateur par courriel + send_email_notification: Notifier l’utilisateur par courriel text: Attention personnalisée type: Action types: @@ -61,7 +63,7 @@ fr: none: Ne rien faire silence: Silence suspend: Suspendre et effacer les données du compte de manière irréversible - warning_preset_id: Utiliser un modèle d'avertissement + warning_preset_id: Utiliser un modèle d’avertissement defaults: autofollow: Invitation à suivre votre compte avatar: Image de profil @@ -72,7 +74,7 @@ fr: context: Contextes du filtre current_password: Mot de passe actuel data: Données - discoverable: Inscrire ce compte dans l'annuaire + discoverable: Inscrire ce compte dans l’annuaire display_name: Nom public email: Adresse courriel expires_in: Expire après @@ -103,7 +105,7 @@ fr: setting_hide_network: Cacher votre réseau setting_noindex: Demander aux moteurs de recherche de ne pas indexer vos informations personnelles setting_reduce_motion: Réduire la vitesse des animations - setting_show_application: Dévoiler le nom de l'application utilisée pour envoyer des pouets + setting_show_application: Dévoiler le nom de l’application utilisée pour envoyer des pouets setting_system_font_ui: Utiliser la police par défaut du système setting_theme: Thème du site setting_unfollow_modal: Afficher une fenêtre de confirmation avant de vous désabonner d’un compte @@ -118,6 +120,8 @@ fr: must_be_follower: Masquer les notifications des personnes qui ne vous suivent pas must_be_following: Masquer les notifications des personnes que vous ne suivez pas must_be_following_dm: Bloquer les messages directs des personnes que vous ne suivez pas + invite_request: + text: Pourquoi voulez-vous vous inscrire ? notification_emails: digest: Envoyer des courriels récapitulatifs favourite: Envoyer un courriel lorsque quelqu’un ajoute mes statuts à ses favoris From 96f0747afe346f2aee358d842f8f9f77638c27a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Reeves?= Date: Thu, 9 May 2019 22:39:27 +0200 Subject: [PATCH 21/23] [Glitch] Add confirm modal for unboosting toots Port fe8a8f779e36e25286b6a7ddc7bcd08e2a4e2890 to glitch-soc Signed-off-by: Thibaut Girka --- .../glitch/containers/status_container.js | 18 +++++++++--------- .../features/ui/components/boost_modal.js | 4 +++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/javascript/flavours/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js index 60636feb4b..98dc5bb872 100644 --- a/app/javascript/flavours/glitch/containers/status_container.js +++ b/app/javascript/flavours/glitch/containers/status_container.js @@ -88,18 +88,18 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ }, onModalReblog (status) { - dispatch(reblog(status)); - }, - - onReblog (status, e) { if (status.get('reblogged')) { dispatch(unreblog(status)); } else { - if (e.shiftKey || !boostModal) { - this.onModalReblog(status); - } else { - dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog })); - } + dispatch(reblog(status)); + } + }, + + onReblog (status, e) { + if (e.shiftKey || !boostModal) { + this.onModalReblog(status); + } else { + dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog })); } }, diff --git a/app/javascript/flavours/glitch/features/ui/components/boost_modal.js b/app/javascript/flavours/glitch/features/ui/components/boost_modal.js index 0a914dce2a..ce7ec2479d 100644 --- a/app/javascript/flavours/glitch/features/ui/components/boost_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/boost_modal.js @@ -10,6 +10,7 @@ import DisplayName from 'flavours/glitch/components/display_name'; import ImmutablePureComponent from 'react-immutable-pure-component'; const messages = defineMessages({ + cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' }, reblog: { id: 'status.reblog', defaultMessage: 'Boost' }, }); @@ -52,6 +53,7 @@ export default class BoostModal extends ImmutablePureComponent { render () { const { status, intl } = this.props; + const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog; return (
    @@ -77,7 +79,7 @@ export default class BoostModal extends ImmutablePureComponent {
    Shift + }} />
    -
    ); From 78ff7e382103b1489e204d8fc3e02790a7d90b8d Mon Sep 17 00:00:00 2001 From: nzws Date: Wed, 8 May 2019 06:53:58 +0900 Subject: [PATCH 22/23] [Glitch] Fix some colors of high contrast theme Signed-off-by: Thibaut Girka --- app/javascript/flavours/glitch/styles/contrast/diff.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/javascript/flavours/glitch/styles/contrast/diff.scss b/app/javascript/flavours/glitch/styles/contrast/diff.scss index 8429103b8a..f78e605975 100644 --- a/app/javascript/flavours/glitch/styles/contrast/diff.scss +++ b/app/javascript/flavours/glitch/styles/contrast/diff.scss @@ -67,3 +67,11 @@ text-decoration: none; } } + +.nothing-here { + color: $darker-text-color; +} + +.public-layout .public-account-header__tabs__tabs .counter.active::after { + border-bottom: 4px solid $ui-highlight-color; +} From 14d855c42985503b525f1a77d00fada3bd15b96f Mon Sep 17 00:00:00 2001 From: Maciek Baron Date: Thu, 9 May 2019 21:03:32 +0100 Subject: [PATCH 23/23] [Glitch] Improve poll link accessibility Port 0402c52f28b73824d7c81c702a16d39fd97808cf to glitch-soc Signed-off-by: Thibaut Girka --- app/javascript/flavours/glitch/styles/polls.scss | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/javascript/flavours/glitch/styles/polls.scss b/app/javascript/flavours/glitch/styles/polls.scss index 315fd5782f..50bb45e7c5 100644 --- a/app/javascript/flavours/glitch/styles/polls.scss +++ b/app/javascript/flavours/glitch/styles/polls.scss @@ -118,11 +118,14 @@ text-decoration: underline; font-size: inherit; - &:hover, - &:focus, - &:active { + &:hover { text-decoration: none; } + + &:active, + &:focus { + background-color: rgba($dark-text-color, .1); + } } .button {