diff --git a/Gemfile b/Gemfile index 9394aa096c..60dc80a9bc 100644 --- a/Gemfile +++ b/Gemfile @@ -114,7 +114,7 @@ group :opentelemetry do gem 'opentelemetry-instrumentation-http', '~> 0.27.0', require: false gem 'opentelemetry-instrumentation-http_client', '~> 0.26.0', require: false gem 'opentelemetry-instrumentation-net_http', '~> 0.26.0', require: false - gem 'opentelemetry-instrumentation-pg', '~> 0.33.0', require: false + gem 'opentelemetry-instrumentation-pg', '~> 0.34.0', require: false gem 'opentelemetry-instrumentation-rack', '~> 0.29.0', require: false gem 'opentelemetry-instrumentation-rails', '~> 0.39.0', require: false gem 'opentelemetry-instrumentation-redis', '~> 0.28.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock index ead5da76e7..ada28236f6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -96,7 +96,7 @@ GEM ast (2.4.3) attr_required (1.0.2) aws-eventstream (1.4.0) - aws-partitions (1.1186.0) + aws-partitions (1.1190.0) aws-sdk-core (3.239.2) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) @@ -105,10 +105,10 @@ GEM bigdecimal jmespath (~> 1, >= 1.6.1) logger - aws-sdk-kms (1.117.0) - aws-sdk-core (~> 3, >= 3.234.0) + aws-sdk-kms (1.118.0) + aws-sdk-core (~> 3, >= 3.239.1) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.205.0) + aws-sdk-s3 (1.206.0) aws-sdk-core (~> 3, >= 3.234.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) @@ -234,7 +234,7 @@ GEM excon (1.3.0) logger fabrication (3.0.0) - faker (3.5.2) + faker (3.5.3) i18n (>= 1.8.11, < 2) faraday (2.14.0) faraday-net_http (>= 2.0, < 3.5) @@ -518,7 +518,7 @@ GEM opentelemetry-semantic_conventions opentelemetry-helpers-sql (0.3.0) opentelemetry-api (~> 1.7) - opentelemetry-helpers-sql-obfuscation (0.5.0) + opentelemetry-helpers-sql-processor (0.3.1) opentelemetry-common (~> 0.21) opentelemetry-instrumentation-action_mailer (0.6.1) opentelemetry-instrumentation-active_support (~> 0.10) @@ -552,9 +552,9 @@ GEM opentelemetry-instrumentation-base (~> 0.25) opentelemetry-instrumentation-net_http (0.26.1) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-pg (0.33.0) + opentelemetry-instrumentation-pg (0.34.1) opentelemetry-helpers-sql - opentelemetry-helpers-sql-obfuscation + opentelemetry-helpers-sql-processor opentelemetry-instrumentation-base (~> 0.25) opentelemetry-instrumentation-rack (0.29.0) opentelemetry-instrumentation-base (~> 0.25) @@ -569,7 +569,7 @@ GEM opentelemetry-instrumentation-concurrent_ruby (~> 0.23) opentelemetry-instrumentation-redis (0.28.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-sidekiq (0.28.0) + opentelemetry-instrumentation-sidekiq (0.28.1) opentelemetry-instrumentation-base (~> 0.25) opentelemetry-registry (0.4.0) opentelemetry-api (~> 1.1) @@ -809,7 +809,7 @@ GEM securerandom (0.4.1) shoulda-matchers (7.0.1) activesupport (>= 7.1) - sidekiq (8.0.9) + sidekiq (8.0.10) connection_pool (>= 2.5.0) json (>= 2.9.0) logger (>= 1.6.2) @@ -1022,7 +1022,7 @@ DEPENDENCIES opentelemetry-instrumentation-http (~> 0.27.0) opentelemetry-instrumentation-http_client (~> 0.26.0) opentelemetry-instrumentation-net_http (~> 0.26.0) - opentelemetry-instrumentation-pg (~> 0.33.0) + opentelemetry-instrumentation-pg (~> 0.34.0) opentelemetry-instrumentation-rack (~> 0.29.0) opentelemetry-instrumentation-rails (~> 0.39.0) opentelemetry-instrumentation-redis (~> 0.28.0) diff --git a/app/javascript/mastodon/components/emoji/index.tsx b/app/javascript/mastodon/components/emoji/index.tsx index 0dff8314ff..8a27b3f1e8 100644 --- a/app/javascript/mastodon/components/emoji/index.tsx +++ b/app/javascript/mastodon/components/emoji/index.tsx @@ -1,9 +1,14 @@ import type { FC } from 'react'; import { useContext, useEffect, useState } from 'react'; +import classNames from 'classnames'; + import { EMOJI_TYPE_CUSTOM } from '@/mastodon/features/emoji/constants'; import { useEmojiAppState } from '@/mastodon/features/emoji/mode'; -import { unicodeHexToUrl } from '@/mastodon/features/emoji/normalize'; +import { + emojiToInversionClassName, + unicodeHexToUrl, +} from '@/mastodon/features/emoji/normalize'; import { isStateLoaded, loadEmojiDataToState, @@ -41,6 +46,9 @@ export const Emoji: FC = ({ }, [appState.currentLocale, state]); const animate = useContext(AnimateEmojiContext); + + const inversionClass = emojiToInversionClassName(code); + const fallback = showFallback ? code : null; // If the code is invalid or we otherwise know it's not valid, show the fallback. @@ -79,7 +87,7 @@ export const Emoji: FC = ({ src={src} alt={state.data.unicode} title={state.data.label} - className='emojione' + className={classNames('emojione', inversionClass)} loading='lazy' /> ); diff --git a/app/javascript/mastodon/features/emoji/constants.ts b/app/javascript/mastodon/features/emoji/constants.ts index 42d22e4054..f770573121 100644 --- a/app/javascript/mastodon/features/emoji/constants.ts +++ b/app/javascript/mastodon/features/emoji/constants.ts @@ -116,3 +116,29 @@ export const EMOJIS_WITH_LIGHT_BORDER = [ '🪽', // 1FAE8 '🪿', // 1FABF ]; + +export const EMOJIS_REQUIRING_INVERSION_IN_LIGHT_MODE = [ + '⛓️', // 26D3-FE0F +]; + +export const EMOJIS_REQUIRING_INVERSION_IN_DARK_MODE = [ + '🔜', // 1F51C + '🔙', // 1F519 + '🔛', // 1F51B + '🔝', // 1F51D + '🔚', // 1F51A + '©️', // 00A9 FE0F + '➰', // 27B0 + '💱', // 1F4B1 + '✔️', // 2714 FE0F + '➗', // 2797 + '💲', // 1F4B2 + '➖', // 2796 + '✖️', // 2716 FE0F + '➕', // 2795 + '®️', // 00AE FE0F + '🕷️', // 1F577 FE0F + '📞', // 1F4DE + '™️', // 2122 FE0F + '〰️', // 3030 FE0F +]; diff --git a/app/javascript/mastodon/features/emoji/emoji.js b/app/javascript/mastodon/features/emoji/emoji.js index 8ca86d16cd..f8fa0ae192 100644 --- a/app/javascript/mastodon/features/emoji/emoji.js +++ b/app/javascript/mastodon/features/emoji/emoji.js @@ -1,5 +1,6 @@ import Trie from 'substring-trie'; +import { getUserTheme, isDarkMode } from '@/mastodon/utils/theme'; import { assetHost } from 'mastodon/utils/config'; import { autoPlayGif } from '../../initial_state'; @@ -97,9 +98,9 @@ const emojifyTextNode = (node, customEmojis) => { const { filename, shortCode } = unicodeMapping[unicode_emoji]; const title = shortCode ? `:${shortCode}:` : ''; - const isSystemTheme = !!document.body?.classList.contains('theme-system'); + const isSystemTheme = getUserTheme() === 'system'; - const theme = (isSystemTheme || document.body?.classList.contains('theme-mastodon-light')) ? 'light' : 'dark'; + const theme = (isSystemTheme || !isDarkMode()) ? 'light' : 'dark'; const imageFilename = emojiFilename(filename, theme); diff --git a/app/javascript/mastodon/features/emoji/mode.ts b/app/javascript/mastodon/features/emoji/mode.ts index 572f2bff37..6950626375 100644 --- a/app/javascript/mastodon/features/emoji/mode.ts +++ b/app/javascript/mastodon/features/emoji/mode.ts @@ -3,6 +3,7 @@ import { createAppSelector, useAppSelector } from '@/mastodon/store'; import { isDevelopment } from '@/mastodon/utils/environment'; +import { isDarkMode } from '@/mastodon/utils/theme'; import { EMOJI_MODE_NATIVE, @@ -27,7 +28,7 @@ export function useEmojiAppState(): EmojiAppState { currentLocale: locale, locales: [locale], mode, - darkTheme: document.body.classList.contains('theme-default'), + darkTheme: isDarkMode(), }; } diff --git a/app/javascript/mastodon/features/emoji/normalize.ts b/app/javascript/mastodon/features/emoji/normalize.ts index a09505e97f..38b01d6905 100644 --- a/app/javascript/mastodon/features/emoji/normalize.ts +++ b/app/javascript/mastodon/features/emoji/normalize.ts @@ -10,6 +10,8 @@ import { SKIN_TONE_CODES, EMOJIS_WITH_DARK_BORDER, EMOJIS_WITH_LIGHT_BORDER, + EMOJIS_REQUIRING_INVERSION_IN_LIGHT_MODE, + EMOJIS_REQUIRING_INVERSION_IN_DARK_MODE, } from './constants'; import type { CustomEmojiMapArg, ExtraCustomEmojiMap } from './types'; @@ -150,6 +152,16 @@ export function twemojiToUnicodeInfo( return hexNumbersToString(mappedCodes); } +export function emojiToInversionClassName(emoji: string): string | null { + if (EMOJIS_REQUIRING_INVERSION_IN_DARK_MODE.includes(emoji)) { + return 'invert-on-dark'; + } + if (EMOJIS_REQUIRING_INVERSION_IN_LIGHT_MODE.includes(emoji)) { + return 'invert-on-light'; + } + return null; +} + export function cleanExtraEmojis(extraEmojis?: CustomEmojiMapArg) { if (!extraEmojis) { return null; diff --git a/app/javascript/mastodon/features/status/components/card.tsx b/app/javascript/mastodon/features/status/components/card.tsx index c6e0c1655a..d060d35c2c 100644 --- a/app/javascript/mastodon/features/status/components/card.tsx +++ b/app/javascript/mastodon/features/status/components/card.tsx @@ -48,8 +48,10 @@ const handleIframeUrl = (html: string, url: string, providerName: string) => { iframeUrl.searchParams.set('autoplay', '1'); iframeUrl.searchParams.set('auto_play', '1'); - if (startTime && providerName === 'YouTube') - iframeUrl.searchParams.set('start', startTime); + if (providerName === 'YouTube') { + iframeUrl.searchParams.set('start', startTime ?? ''); + iframe.referrerPolicy = 'strict-origin-when-cross-origin'; + } iframe.src = iframeUrl.href; diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 5c64f8e0fc..ed22eda8d4 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -135,6 +135,7 @@ "annual_report.summary.new_posts.new_posts": "новыя допісы", "annual_report.summary.percentile.text": "Гэта падымае Вас у топ карыстальнікаў {domain}.", "annual_report.summary.percentile.we_wont_tell_bernie": "КДБ пра гэта не даведаецца.", + "annual_report.summary.share_message": "Мой архетып – {archetype}!", "annual_report.summary.thanks": "Дзякуй за ўдзел у Mastodon!", "attachments_list.unprocessed": "(неапрацаваны)", "audio.hide": "Схаваць аўдыя", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 73ee79e6b0..54b387061e 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -147,7 +147,7 @@ "block_modal.they_will_know": "Das Profil wird erkennen können, dass du es blockiert hast.", "block_modal.title": "Profil blockieren?", "block_modal.you_wont_see_mentions": "Du wirst keine Beiträge sehen, die dieses Profil erwähnen.", - "boost_modal.combo": "Mit {combo} erscheint dieses Fenster beim nächsten Mal nicht mehr", + "boost_modal.combo": "Mit {combo} erscheint dieses Fenster nicht mehr", "boost_modal.reblog": "Beitrag teilen?", "boost_modal.undo_reblog": "Beitrag nicht mehr teilen?", "bundle_column_error.copy_stacktrace": "Fehlerbericht kopieren", @@ -200,7 +200,7 @@ "column_search.cancel": "Abbrechen", "community.column_settings.local_only": "Nur lokal", "community.column_settings.media_only": "Nur Beiträge mit Medien", - "community.column_settings.remote_only": "Nur andere Mastodon-Server", + "community.column_settings.remote_only": "Nur andere Server im Fediverse", "compose.error.blank_post": "Beitrag muss einen Inhalt haben.", "compose.language.change": "Sprache festlegen", "compose.language.search": "Sprachen suchen …", @@ -213,13 +213,13 @@ "compose_form.lock_disclaimer": "Dein Profil ist nicht {locked}. Andere können dir folgen und deine Beiträge sehen, die nur für Follower bestimmt sind.", "compose_form.lock_disclaimer.lock": "geschützt", "compose_form.placeholder": "Was gibts Neues?", - "compose_form.poll.duration": "Umfragedauer", + "compose_form.poll.duration": "Laufzeit", "compose_form.poll.multiple": "Mehrfachauswahl", "compose_form.poll.option_placeholder": "{number}. Auswahl", "compose_form.poll.single": "Einfachauswahl", "compose_form.poll.switch_to_multiple": "Mehrfachauswahl erlauben", "compose_form.poll.switch_to_single": "Nur Einfachauswahl erlauben", - "compose_form.poll.type": "Art", + "compose_form.poll.type": "Typ", "compose_form.publish": "Veröffentlichen", "compose_form.reply": "Antworten", "compose_form.save_changes": "Aktualisieren", @@ -232,7 +232,7 @@ "confirmations.delete.message": "Möchtest du diesen Beitrag wirklich löschen?", "confirmations.delete.title": "Beitrag löschen?", "confirmations.delete_list.confirm": "Löschen", - "confirmations.delete_list.message": "Möchtest du diese Liste für immer löschen?", + "confirmations.delete_list.message": "Bist du dir sicher, dass du diese Liste endgültig löschen möchtest?", "confirmations.delete_list.title": "Liste löschen?", "confirmations.discard_draft.confirm": "Verwerfen und fortfahren", "confirmations.discard_draft.edit.cancel": "Bearbeitung fortsetzen", @@ -247,31 +247,31 @@ "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.logout.confirm": "Abmelden", - "confirmations.logout.message": "Bist du sicher, dass du dich abmelden möchtest?", + "confirmations.logout.message": "Möchtest du dich wirklich ausloggen?", "confirmations.logout.title": "Abmelden?", "confirmations.missing_alt_text.confirm": "Bildbeschreibung hinzufügen", "confirmations.missing_alt_text.message": "Dein Beitrag enthält Medien ohne Bildbeschreibung. Mit ALT-Texten erreichst Du auch Menschen, die blind oder sehbehindert sind.", "confirmations.missing_alt_text.secondary": "Trotzdem veröffentlichen", "confirmations.missing_alt_text.title": "Bildbeschreibung hinzufügen?", "confirmations.mute.confirm": "Stummschalten", - "confirmations.private_quote_notify.cancel": "Zurück zum Bearbeiten", + "confirmations.private_quote_notify.cancel": "Zurück zur Bearbeitung", "confirmations.private_quote_notify.confirm": "Beitrag veröffentlichen", "confirmations.private_quote_notify.do_not_show_again": "Diesen Hinweis nicht mehr anzeigen", "confirmations.private_quote_notify.message": "Dein Beitrag wird von dem zitierten sowie den erwähnten Profilen gesehen werden können, auch wenn sie dir nicht folgen.", "confirmations.private_quote_notify.title": "Mit Followern und erwähnten Profilen teilen?", - "confirmations.quiet_post_quote_info.dismiss": "Nicht mehr anzeigen", + "confirmations.quiet_post_quote_info.dismiss": "Nicht erneut erinnern", "confirmations.quiet_post_quote_info.got_it": "Verstanden", "confirmations.quiet_post_quote_info.message": "Beim Zitieren eines Beitrags, dessen Sichtbarkeit „Öffentlich (still)“ ist, wird auch dein Beitrag, der das Zitat enthält, aus den Trends und öffentlichen Timelines ausgeblendet.", "confirmations.quiet_post_quote_info.title": "Zitieren eines Beitrags mit der Sichtbarkeit „Öffentlich (still)“", "confirmations.redraft.confirm": "Löschen und neu erstellen", "confirmations.redraft.message": "Möchtest du diesen Beitrag wirklich löschen und neu verfassen? Alle Favoriten sowie die bisher geteilten Beiträge werden verloren gehen und Antworten auf den ursprünglichen Beitrag verlieren den Zusammenhang.", - "confirmations.redraft.title": "Beitrag löschen und neu verfassen?", + "confirmations.redraft.title": "Beitrag löschen & neu verfassen?", "confirmations.remove_from_followers.confirm": "Follower entfernen", "confirmations.remove_from_followers.message": "{name} wird dir nicht länger folgen. Bist du dir sicher?", "confirmations.remove_from_followers.title": "Follower entfernen?", "confirmations.revoke_quote.confirm": "Zitat entfernen", "confirmations.revoke_quote.message": "Diese Aktion kann nicht rückgängig gemacht werden.", - "confirmations.revoke_quote.title": "Zitieren meines Beitrags entfernen?", + "confirmations.revoke_quote.title": "Mein Zitat aus diesem Beitrag entfernen?", "confirmations.unblock.confirm": "Blockierung aufheben", "confirmations.unblock.title": "Blockierung von {name} aufheben?", "confirmations.unfollow.confirm": "Entfolgen", @@ -309,7 +309,7 @@ "domain_pill.activitypub_lets_connect": "Somit kannst du dich nicht nur auf Mastodon mit Leuten verbinden und mit ihnen interagieren, sondern über alle sozialen Apps hinweg.", "domain_pill.activitypub_like_language": "ActivityPub ist sozusagen die Sprache, die Mastodon mit anderen sozialen Netzwerken spricht.", "domain_pill.server": "Server", - "domain_pill.their_handle": "Die vollständige Adresse:", + "domain_pill.their_handle": "Vollständige Adresse:", "domain_pill.their_server": "Die digitale Heimat, in der sich alle Beiträge dieses Profils befinden.", "domain_pill.their_username": "Die eindeutige Identifizierung auf einem Server. Es ist möglich, denselben Profilnamen auf verschiedenen Servern im Fediverse zu finden.", "domain_pill.username": "Profilname", @@ -327,7 +327,7 @@ "emoji_button.custom": "Spezielle Emojis dieses Servers", "emoji_button.flags": "Flaggen", "emoji_button.food": "Essen & Trinken", - "emoji_button.label": "Emoji einfügen", + "emoji_button.label": "Emoji hinzufügen", "emoji_button.nature": "Natur", "emoji_button.not_found": "Keine passenden Emojis gefunden", "emoji_button.objects": "Gegenstände", @@ -349,8 +349,8 @@ "empty_column.community": "Die lokale Timeline ist leer. Schreibe einen öffentlichen Beitrag, um den Stein ins Rollen zu bringen!", "empty_column.direct": "Du hast noch keine privaten Erwähnungen. Sobald du eine sendest oder erhältst, wird sie hier erscheinen.", "empty_column.disabled_feed": "Diesen Feed haben deine Server-Administrator*innen deaktiviert.", - "empty_column.domain_blocks": "Du hast noch keine Domains blockiert.", - "empty_column.explore_statuses": "Momentan ist nichts im Trend. Schau später wieder vorbei!", + "empty_column.domain_blocks": "Du hast bisher keine Domains blockiert.", + "empty_column.explore_statuses": "Momentan trendet nichts. Schau später wieder vorbei!", "empty_column.favourited_statuses": "Du hast noch keine Beiträge favorisiert. Sobald du einen favorisierst, wird er hier erscheinen.", "empty_column.favourites": "Diesen Beitrag hat bisher noch niemand favorisiert. Sobald es jemand tut, wird das Profil hier erscheinen.", "empty_column.follow_requests": "Es liegen derzeit keine Follower-Anfragen vor. Sobald du eine erhältst, wird sie hier erscheinen.", @@ -458,7 +458,7 @@ "hints.profiles.see_more_posts": "Weitere Beiträge auf {domain} ansehen", "home.column_settings.show_quotes": "Zitierte Beiträge anzeigen", "home.column_settings.show_reblogs": "Geteilte Beiträge anzeigen", - "home.column_settings.show_replies": "Antworten anzeigen", + "home.column_settings.show_replies": "Antworten zu Beiträgen anzeigen", "home.hide_announcements": "Ankündigungen ausblenden", "home.pending_critical_update.body": "Bitte aktualisiere deinen Mastodon-Server so schnell wie möglich!", "home.pending_critical_update.link": "Updates ansehen", diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json index 1be1ed615b..d49b7d3629 100644 --- a/app/javascript/mastodon/locales/en-GB.json +++ b/app/javascript/mastodon/locales/en-GB.json @@ -135,6 +135,7 @@ "annual_report.summary.new_posts.new_posts": "new posts", "annual_report.summary.percentile.text": "That puts you in the topof {domain} users.", "annual_report.summary.percentile.we_wont_tell_bernie": "We won't tell Bernie.", + "annual_report.summary.share_message": "I got the {archetype} archetype!", "annual_report.summary.thanks": "Thanks for being part of Mastodon!", "attachments_list.unprocessed": "(unprocessed)", "audio.hide": "Hide audio", diff --git a/app/javascript/mastodon/locales/fr-CA.json b/app/javascript/mastodon/locales/fr-CA.json index 6da28963d6..1975ce0c89 100644 --- a/app/javascript/mastodon/locales/fr-CA.json +++ b/app/javascript/mastodon/locales/fr-CA.json @@ -626,7 +626,7 @@ "notification.follow_request.name_and_others": "{name} et {count, plural, one {# autre} other {# autres}} ont demandé à vous suivre", "notification.label.mention": "Mention", "notification.label.private_mention": "Mention privée", - "notification.label.private_reply": "Répondre en privé", + "notification.label.private_reply": "Réponse privée", "notification.label.quote": "{name} a cité votre publication", "notification.label.reply": "Réponse", "notification.mention": "Mention", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index ebe17a1133..2ad548d9a4 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -626,7 +626,7 @@ "notification.follow_request.name_and_others": "{name} et {count, plural, one {# autre} other {# autres}} ont demandé à vous suivre", "notification.label.mention": "Mention", "notification.label.private_mention": "Mention privée", - "notification.label.private_reply": "Répondre en privé", + "notification.label.private_reply": "Réponse privée", "notification.label.quote": "{name} a cité votre publication", "notification.label.reply": "Réponse", "notification.mention": "Mention", diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json index 66d2e460ac..7172aaacf5 100644 --- a/app/javascript/mastodon/locales/ga.json +++ b/app/javascript/mastodon/locales/ga.json @@ -56,7 +56,7 @@ "account.follows_you": "Leanann tú", "account.go_to_profile": "Téigh go dtí próifíl", "account.hide_reblogs": "Folaigh moltaí ó @{name}", - "account.in_memoriam": "Cuimhneachán.", + "account.in_memoriam": "Ón tseanaimsir.", "account.joined_short": "Cláraithe", "account.languages": "Athraigh teangacha foscríofa", "account.link_verified_on": "Seiceáladh úinéireacht an naisc seo ar {date}", @@ -135,6 +135,7 @@ "annual_report.summary.new_posts.new_posts": "postanna nua", "annual_report.summary.percentile.text": "Cuireann sé sin i mbarr úsáideoirí {domain}. thú", "annual_report.summary.percentile.we_wont_tell_bernie": "Ní inseoidh muid do Bernie.", + "annual_report.summary.share_message": "Fuair ​​mé an t-archetíopa {archetype}!", "annual_report.summary.thanks": "Go raibh maith agat as a bheith mar chuid de Mastodon!", "attachments_list.unprocessed": "(neamhphróiseáilte)", "audio.hide": "Cuir fuaim i bhfolach", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 7948374732..dad94113a9 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -135,6 +135,7 @@ "annual_report.summary.new_posts.new_posts": "novas publicacións", "annual_report.summary.percentile.text": "Sitúante no top das usuarias de {domain}.", "annual_report.summary.percentile.we_wont_tell_bernie": "Moito tes que contarnos!", + "annual_report.summary.share_message": "Resulta que son… {archetype}!", "annual_report.summary.thanks": "Grazas por ser parte de Mastodon!", "attachments_list.unprocessed": "(sen procesar)", "audio.hide": "Agochar audio", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 6ed16f8517..d6a3d994ea 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -113,6 +113,10 @@ "alt_text_modal.describe_for_people_with_visual_impairments": "Descrivi questo per le persone con disabilità visive…", "alt_text_modal.done": "Fatto", "announcement.announcement": "Annuncio", + "annual_report.announcement.action_build": "Costruisci il mio Wrapstodon", + "annual_report.announcement.action_view": "Visualizza il mio Wrapstodon", + "annual_report.announcement.description": "Scopri di più sul tuo coinvolgimento su Mastodon nell'ultimo anno.", + "annual_report.announcement.title": "Wrapstodon {year} è arrivato", "annual_report.summary.archetype.booster": "Cacciatore/trice di tendenze", "annual_report.summary.archetype.lurker": "L'osservatore/trice", "annual_report.summary.archetype.oracle": "L'oracolo", @@ -131,6 +135,7 @@ "annual_report.summary.new_posts.new_posts": "nuovi post", "annual_report.summary.percentile.text": "Ciò ti colloca in cimaagli utenti di {domain}.", "annual_report.summary.percentile.we_wont_tell_bernie": "Non lo diremo a Bernie.", + "annual_report.summary.share_message": "Ho ottenuto l'archetipo: {archetype}!", "annual_report.summary.thanks": "Grazie per far parte di Mastodon!", "attachments_list.unprocessed": "(non elaborato)", "audio.hide": "Nascondi audio", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 3715de9091..252ab60cca 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -14,7 +14,7 @@ "about.powered_by": "Decentralizuota socialinė medija, veikianti pagal „{mastodon}“", "about.rules": "Serverio taisyklės", "account.account_note_header": "Asmeninė pastaba", - "account.add_or_remove_from_list": "Pridėti arba pašalinti iš sąrašų", + "account.add_or_remove_from_list": "Įtraukti arba šalinti iš sąrašų", "account.badges.bot": "Automatizuotas", "account.badges.group": "Grupė", "account.block": "Blokuoti @{name}", @@ -135,7 +135,7 @@ "annual_report.summary.new_posts.new_posts": "nauji įrašai", "annual_report.summary.percentile.text": "Tai reiškia, kad esate tarppopuliariausių {domain} naudotojų.", "annual_report.summary.percentile.we_wont_tell_bernie": "Mes nesakysime Bernie.", - "annual_report.summary.share_message": "Aš gavau {archetype}!", + "annual_report.summary.share_message": "Aš gavau „{archetype}“!", "annual_report.summary.thanks": "Dėkojame, kad esate „Mastodon“ dalis!", "attachments_list.unprocessed": "(neapdorotas)", "audio.hide": "Slėpti garsą", @@ -921,7 +921,7 @@ "status.more": "Daugiau", "status.mute": "Nutildyti @{name}", "status.mute_conversation": "Nutildyti pokalbį", - "status.open": "Išplėsti šį įrašą", + "status.open": "Išskleisti šį įrašą", "status.pin": "Prisegti prie profilio", "status.quote": "Paminėjimai", "status.quote.cancel": "Atšaukti paminėjimą", @@ -1016,14 +1016,21 @@ "video.pause": "Pristabdyti", "video.play": "Leisti", "video.skip_backward": "Praleisti atgal", + "video.skip_forward": "Praleisti į priekį", + "video.unmute": "Atšaukti nutildymą", + "video.volume_down": "Patildyti", + "video.volume_up": "Pagarsinti", + "visibility_modal.button_title": "Nustatyti matomumą", "visibility_modal.direct_quote_warning.text": "Jei išsaugosite dabartinius nustatymus, įterpta citata bus konvertuota į nuorodą.", "visibility_modal.direct_quote_warning.title": "Cituojami įrašai negali būti įterpiami į privačius paminėjimus", "visibility_modal.helper.direct_quoting": "Privatūs paminėjimai, parašyti platformoje „Mastodon“, negali būti cituojami kitų.", "visibility_modal.helper.privacy_private_self_quote": "Privačių įrašų paminėjimai negali būti skelbiami viešai.", "visibility_modal.helper.private_quoting": "Tik sekėjams skirti įrašai, parašyti platformoje „Mastodon“, negali būti cituojami kitų.", "visibility_modal.helper.unlisted_quoting": "Kai žmonės jus cituos, jų įrašai taip pat bus paslėpti iš populiariausių naujienų srauto.", + "visibility_modal.privacy_label": "Matomumas", "visibility_modal.quote_followers": "Tik sekėjai", "visibility_modal.quote_label": "Kas gali cituoti", "visibility_modal.quote_nobody": "Tik aš", - "visibility_modal.quote_public": "Visi" + "visibility_modal.quote_public": "Visi", + "visibility_modal.save": "Išsaugoti" } diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index c674509368..54a993acf6 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -135,6 +135,7 @@ "annual_report.summary.new_posts.new_posts": "yeni gönderiler", "annual_report.summary.percentile.text": "{domain} kullanıcılarınınüst dilimindesiniz", "annual_report.summary.percentile.we_wont_tell_bernie": "Bernie'ye söylemeyiz.", + "annual_report.summary.share_message": "{archetype} arketipindeyim!", "annual_report.summary.thanks": "Mastodon'un bir parçası olduğunuz için teşekkürler!", "attachments_list.unprocessed": "(işlenmemiş)", "audio.hide": "Sesi gizle", diff --git a/app/javascript/mastodon/models/annual_report.ts b/app/javascript/mastodon/models/annual_report.ts index a2c0c51786..819212efeb 100644 --- a/app/javascript/mastodon/models/annual_report.ts +++ b/app/javascript/mastodon/models/annual_report.ts @@ -42,13 +42,6 @@ interface AnnualReportV2 { time_series: TimeSeriesMonth[]; top_hashtags: NameAndCount[]; top_statuses: TopStatuses; - most_used_apps: NameAndCount[]; - type_distribution: { - total: number; - reblogs: number; - replies: number; - standalone: number; - }; } export type AnnualReport = { diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index 784050d942..c7e27abd45 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -530,7 +530,7 @@ export const composeReducer = (state = initialState, action) => { map.set('sensitive', action.status.get('sensitive')); map.set('language', action.status.get('language')); map.set('id', null); - map.set('quoted_status_id', action.status.getIn(['quote', 'quoted_status'])); + map.set('quoted_status_id', action.status.getIn(['quote', 'quoted_status'], null)); // Mastodon-authored posts can be expected to have at most one automatic approval policy map.set('quote_policy', action.status.getIn(['quote_approval', 'automatic', 0]) || 'nobody'); @@ -567,7 +567,7 @@ export const composeReducer = (state = initialState, action) => { map.set('idempotencyKey', uuid()); map.set('sensitive', action.status.get('sensitive')); map.set('language', action.status.get('language')); - map.set('quoted_status_id', action.status.getIn(['quote', 'quoted_status'])); + map.set('quoted_status_id', action.status.getIn(['quote', 'quoted_status'], null)); // Mastodon-authored posts can be expected to have at most one automatic approval policy map.set('quote_policy', action.status.getIn(['quote_approval', 'automatic', 0]) || 'nobody'); diff --git a/app/javascript/mastodon/utils/theme.ts b/app/javascript/mastodon/utils/theme.ts new file mode 100644 index 0000000000..767d97cf5c --- /dev/null +++ b/app/javascript/mastodon/utils/theme.ts @@ -0,0 +1,13 @@ +export function getUserTheme() { + const { userTheme } = document.documentElement.dataset; + return userTheme; +} + +export function isDarkMode() { + const { userTheme } = document.documentElement.dataset; + return ( + (userTheme === 'system' && + window.matchMedia('(prefers-color-scheme: dark)').matches) || + userTheme !== 'mastodon-light' + ); +} diff --git a/app/javascript/styles/application.scss b/app/javascript/styles/application.scss index a38653cf1c..cc23627a15 100644 --- a/app/javascript/styles/application.scss +++ b/app/javascript/styles/application.scss @@ -1,2 +1 @@ -@use 'mastodon/variables'; @use 'common'; diff --git a/app/javascript/styles/common.scss b/app/javascript/styles/common.scss index b56fa3f579..5f5077627e 100644 --- a/app/javascript/styles/common.scss +++ b/app/javascript/styles/common.scss @@ -1,3 +1,4 @@ +@use 'mastodon/variables'; @use 'mastodon/mixins'; @use 'fonts/roboto'; @use 'fonts/roboto-mono'; @@ -21,5 +22,4 @@ @use 'mastodon/admin'; @use 'mastodon/dashboard'; @use 'mastodon/rtl'; -@use 'mastodon/accessibility'; @use 'mastodon/rich_text'; diff --git a/app/javascript/styles/contrast.scss b/app/javascript/styles/contrast.scss index d89eaa610f..93bbfed080 100644 --- a/app/javascript/styles/contrast.scss +++ b/app/javascript/styles/contrast.scss @@ -1,3 +1,2 @@ -@use 'mastodon/variables'; @use 'common'; @use 'mastodon/high-contrast'; diff --git a/app/javascript/styles/mastodon-light.scss b/app/javascript/styles/mastodon-light.scss index 11a92fb873..cc23627a15 100644 --- a/app/javascript/styles/mastodon-light.scss +++ b/app/javascript/styles/mastodon-light.scss @@ -1,4 +1 @@ -@use 'mastodon/variables' with ( - $emojis-requiring-inversion: 'chains' -); @use 'common'; diff --git a/app/javascript/styles/mastodon/_variables.scss b/app/javascript/styles/mastodon/_variables.scss index a948dbc41c..d561f71454 100644 --- a/app/javascript/styles/mastodon/_variables.scss +++ b/app/javascript/styles/mastodon/_variables.scss @@ -20,8 +20,3 @@ $no-columns-breakpoint: 600px; $font-sans-serif: 'mastodon-font-sans-serif' !default; $font-display: 'mastodon-font-display' !default; $font-monospace: 'mastodon-font-monospace' !default; - -$emojis-requiring-inversion: 'back' 'copyright' 'curly_loop' 'currency_exchange' - 'end' 'heavy_check_mark' 'heavy_division_sign' 'heavy_dollar_sign' - 'heavy_minus_sign' 'heavy_multiplication_x' 'heavy_plus_sign' 'on' - 'registered' 'soon' 'spider' 'telephone_receiver' 'tm' 'top' 'wavy_dash' !default; diff --git a/app/javascript/styles/mastodon/accessibility.scss b/app/javascript/styles/mastodon/accessibility.scss deleted file mode 100644 index 7cd2d4eae3..0000000000 --- a/app/javascript/styles/mastodon/accessibility.scss +++ /dev/null @@ -1,13 +0,0 @@ -@use 'variables' as *; - -%emoji-color-inversion { - filter: invert(1); -} - -.emojione { - @each $emoji in $emojis-requiring-inversion { - &[title=':#{$emoji}:'] { - @extend %emoji-color-inversion; - } - } -} diff --git a/app/javascript/styles/mastodon/basics.scss b/app/javascript/styles/mastodon/basics.scss index d28150f12a..8cc06a50b3 100644 --- a/app/javascript/styles/mastodon/basics.scss +++ b/app/javascript/styles/mastodon/basics.scss @@ -10,6 +10,8 @@ html { --outline-focus-default: 2px solid var(--color-text-brand); --avatar-border-radius: 8px; + --max-media-height-small: 460px; + --max-media-height-large: 566px; // Variable for easily inverting directional UI elements, --text-x-direction: 1; diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index ed2403b045..5344b1826a 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -7165,7 +7165,18 @@ a.status-card { // The size of single images is determined by their // aspect-ratio, applied via inline style attribute width: initial; - max-height: 460px; + + // Prevent extremely tall images from essentially becoming invisible + min-width: 120px; + max-height: var(--max-media-height-small); + + @container (width > 500px) { + max-height: var(--max-media-height-large); + } + + .detailed-status & { + max-height: calc(2 * var(--max-media-height-large)); + } } &--layout-2 { @@ -7500,7 +7511,7 @@ a.status-card { position: relative; color: var(--color-text-on-media); background: var(--color-bg-media); - max-height: 460px; + max-height: var(--max-media-height-small); border-radius: 8px; box-sizing: border-box; display: flex; @@ -7508,6 +7519,10 @@ a.status-card { outline-offset: -1px; z-index: 2; + @container (width > 500px) { + max-height: var(--max-media-height-large); + } + video { display: block; z-index: -2; diff --git a/app/javascript/styles/mastodon/theme/_utils.scss b/app/javascript/styles/mastodon/theme/_utils.scss index 1c03c2f65c..4c207c5094 100644 --- a/app/javascript/styles/mastodon/theme/_utils.scss +++ b/app/javascript/styles/mastodon/theme/_utils.scss @@ -1,3 +1,15 @@ @function css-alpha($base-color, $amount) { @return #{rgb(from $base-color r g b / $amount)}; } + +@mixin invert-on-light { + .invert-on-light { + filter: invert(1); + } +} + +@mixin invert-on-dark { + .invert-on-dark { + filter: invert(1); + } +} diff --git a/app/javascript/styles/mastodon/theme/index.scss b/app/javascript/styles/mastodon/theme/index.scss index d78b7e2a99..8e275e514a 100644 --- a/app/javascript/styles/mastodon/theme/index.scss +++ b/app/javascript/styles/mastodon/theme/index.scss @@ -1,6 +1,7 @@ @use 'base'; @use 'dark'; @use 'light'; +@use 'utils'; html { @include base.palette; @@ -10,6 +11,7 @@ html { @media (prefers-color-scheme: dark) { @include dark.tokens; + @include utils.invert-on-dark; @media (prefers-contrast: more) { @include dark.contrast-overrides; @@ -18,6 +20,7 @@ html { @media (prefers-color-scheme: light) { @include light.tokens; + @include utils.invert-on-light; @media (prefers-contrast: more) { @include light.contrast-overrides; @@ -33,6 +36,7 @@ html:where( color-scheme: dark; @include dark.tokens; + @include utils.invert-on-dark; } html[data-user-theme='contrast'], @@ -45,4 +49,5 @@ html:where([data-user-theme='mastodon-light']) { color-scheme: light; @include light.tokens; + @include utils.invert-on-light; } diff --git a/app/lib/annual_report.rb b/app/lib/annual_report.rb index 0acd51eb17..a9c9135ed4 100644 --- a/app/lib/annual_report.rb +++ b/app/lib/annual_report.rb @@ -5,9 +5,7 @@ class AnnualReport SOURCES = [ AnnualReport::Archetype, - AnnualReport::TypeDistribution, AnnualReport::TopStatuses, - AnnualReport::MostUsedApps, AnnualReport::TimeSeries, AnnualReport::TopHashtags, ].freeze @@ -22,7 +20,7 @@ class AnnualReport return unless Mastodon::Feature.wrapstodon_enabled? datetime = Time.now.utc - datetime.year if datetime.month == 12 && (1..31).cover?(datetime.day) + datetime.year if datetime.month == 12 && (10..31).cover?(datetime.day) end def initialize(account, year) diff --git a/app/lib/annual_report/most_used_apps.rb b/app/lib/annual_report/most_used_apps.rb deleted file mode 100644 index a2e1aca452..0000000000 --- a/app/lib/annual_report/most_used_apps.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -class AnnualReport::MostUsedApps < AnnualReport::Source - SET_SIZE = 10 - - def generate - { - most_used_apps: most_used_apps.map do |(name, count)| - { - name: name, - count: count, - } - end, - } - end - - private - - def most_used_apps - report_statuses.joins(:application).group(oauth_applications: [:name]).order(count_all: :desc).limit(SET_SIZE).count - end -end diff --git a/app/lib/annual_report/top_hashtags.rb b/app/lib/annual_report/top_hashtags.rb index f3a2160341..9ed0057bdd 100644 --- a/app/lib/annual_report/top_hashtags.rb +++ b/app/lib/annual_report/top_hashtags.rb @@ -2,7 +2,7 @@ class AnnualReport::TopHashtags < AnnualReport::Source MINIMUM_TAGGINGS = 1 - SET_SIZE = 5 + SET_SIZE = 1 def generate { diff --git a/app/lib/annual_report/type_distribution.rb b/app/lib/annual_report/type_distribution.rb deleted file mode 100644 index 0534055c28..0000000000 --- a/app/lib/annual_report/type_distribution.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -class AnnualReport::TypeDistribution < AnnualReport::Source - def generate - { - type_distribution: { - total: report_statuses.count, - reblogs: report_statuses.only_reblogs.count, - replies: report_statuses.where.not(in_reply_to_id: nil).not_replying_to_account(@account).count, - standalone: report_statuses.without_replies.without_reblogs.count, - }, - } - end -end diff --git a/config/locales/be.yml b/config/locales/be.yml index c8ba5dde06..3212b7cbb3 100644 --- a/config/locales/be.yml +++ b/config/locales/be.yml @@ -2273,3 +2273,5 @@ be: not_supported: Гэты браўзер не падтрымлівае ключы бяспекі otp_required: Каб выкарыстоўваць ключы бяспекі, спачатку ўключыце двухфактарную аўтэнтыфікацыю. registered_on: Зарэгістраваны %{date} + wrapstodon: + title: Вынікадон %{year} для %{name} diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 4a921bedc2..7a08b1c63e 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -2185,3 +2185,5 @@ en-GB: not_supported: This browser doesn't support security keys otp_required: To use security keys please enable two-factor authentication first. registered_on: Registered on %{date} + wrapstodon: + title: Wrapstodon %{year} for %{name} diff --git a/config/locales/eo.yml b/config/locales/eo.yml index 0ae35b5564..04d3e9955a 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -1321,7 +1321,7 @@ eo: warning: before: 'Antau ol dauri, legu ĉi tiujn notojn zorgeme:' caches: Enhavo kiu kaŝmemorigitas de aliaj serviloj eble restas - data_removal: Viaj afiŝoj kaj aliaj informoj estos forigita por eterne + data_removal: Viaj afiŝoj kaj aliaj informoj estos forigita por ĉiam email_change_html: Vi povas ŝanĝi vian retadreson sen forigi vian konton email_contact_html: Se ĝi ankoraŭ ne alvenas, vi povas retpoŝti al %{email} por helpo email_reconfirmation_html: Se vi ne ricevas la konfirmretpoŝton, vi povas denove peti diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 52db9182d7..b9c4ba5427 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -2185,3 +2185,5 @@ gl: not_supported: Este navegador non ten soporte para chaves de seguridade otp_required: Para usar chaves de seguridade tes que activar primeiro o segundo factor. registered_on: Rexistrado o %{date} + wrapstodon: + title: Wrapstodon %{year} de %{name} diff --git a/config/locales/it.yml b/config/locales/it.yml index b3a4fe0db8..1be6d50ad3 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -1706,16 +1706,22 @@ it: body: 'Sei stato menzionato da %{name} su:' subject: Sei stato menzionato da %{name} title: Nuova menzione + moderation_warning: + subject: Hai ricevuto un avviso di moderazione poll: subject: Un sondaggio da %{name} è terminato quote: body: 'Il tuo post è stato citato da %{name}:' subject: "%{name} ha citato il tuo post" title: Nuova citazione + quoted_update: + subject: "%{name} ha modificato un post che hai citato" reblog: body: 'Il tuo status è stato condiviso da %{name}:' subject: "%{name} ha condiviso il tuo status" title: Nuova condivisione + severed_relationships: + subject: Hai perso le connessioni a causa di una decisione della moderazione status: subject: "%{name} ha appena pubblicato un post" update: @@ -2179,3 +2185,5 @@ it: not_supported: Questo browser non supporta le chiavi di sicurezza otp_required: Per utilizzare le chiavi di sicurezza, prima abilita l'autenticazione a due fattori. registered_on: Registrato il %{date} + wrapstodon: + title: Wrapstodon %{year} per %{name} diff --git a/config/locales/simple_form.eo.yml b/config/locales/simple_form.eo.yml index f2ae3be28e..aad8898924 100644 --- a/config/locales/simple_form.eo.yml +++ b/config/locales/simple_form.eo.yml @@ -49,7 +49,7 @@ eo: email: Vi ricevos konfirman retpoŝton header: WEBP, PNG, GIF aŭ JPG. Maksimume %{size}. Malgrandiĝos al %{dimensions}px inbox_url: Kopiu la URL de la ĉefpaĝo de la ripetilo, kiun vi volas uzi - irreversible: La filtritaj mesaĝoj malaperos por eterne, eĉ se la filtrilo poste estas forigita + irreversible: La filtritaj mesaĝoj malaperos por ĉiam, eĉ se la filtrilo poste estas forigita locale: La lingvo de la fasado, retpoŝtaĵoj, kaj sciigoj password: Uzu almenaŭ 8 signojn phrase: Estos provita senzorge pri la uskleco de teksto aŭ averto pri enhavo de mesaĝo diff --git a/spec/helpers/theme_helper_spec.rb b/spec/helpers/theme_helper_spec.rb index 875a15321f..c94bf303d8 100644 --- a/spec/helpers/theme_helper_spec.rb +++ b/spec/helpers/theme_helper_spec.rb @@ -12,7 +12,8 @@ RSpec.describe ThemeHelper do it 'returns the mastodon-light and application stylesheets with correct color schemes' do expect(html_links.first.attributes.symbolize_keys) .to include( - href: have_attributes(value: match(/mastodon-light/)), + # This is now identical to the default theme & will be unified very soon + href: have_attributes(value: match(/default/)), media: have_attributes(value: 'not all and (prefers-color-scheme: dark)') ) expect(html_links.last.attributes.symbolize_keys) diff --git a/spec/lib/annual_report/most_used_apps_spec.rb b/spec/lib/annual_report/most_used_apps_spec.rb deleted file mode 100644 index ab7022ef20..0000000000 --- a/spec/lib/annual_report/most_used_apps_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe AnnualReport::MostUsedApps do - describe '#generate' do - subject { described_class.new(account, Time.zone.now.year) } - - context 'with an inactive account' do - let(:account) { Fabricate :account } - - it 'builds a report for an account' do - expect(subject.generate) - .to include( - most_used_apps: be_an(Array).and(be_empty) - ) - end - end - - context 'with an active account' do - let(:account) { Fabricate :account } - - let(:application) { Fabricate :application, name: 'App' } - let(:most_application) { Fabricate :application, name: 'Most App' } - - before do - _other = Fabricate :status - Fabricate.times 2, :status, account: account, application: application - Fabricate.times 3, :status, account: account, application: most_application - end - - it 'builds a report for an account' do - expect(subject.generate) - .to include( - most_used_apps: eq( - [ - { name: most_application.name, count: 3 }, - { name: application.name, count: 2 }, - ] - ) - ) - end - end - end -end diff --git a/spec/lib/annual_report/top_hashtags_spec.rb b/spec/lib/annual_report/top_hashtags_spec.rb index b9cc9392ed..1438999392 100644 --- a/spec/lib/annual_report/top_hashtags_spec.rb +++ b/spec/lib/annual_report/top_hashtags_spec.rb @@ -44,7 +44,6 @@ RSpec.describe AnnualReport::TopHashtags do top_hashtags: eq( [ { name: most_tag.name, count: 3 }, - { name: tag.name, count: 2 }, ] ) ) diff --git a/spec/lib/annual_report/type_distribution_spec.rb b/spec/lib/annual_report/type_distribution_spec.rb deleted file mode 100644 index 89a31fb207..0000000000 --- a/spec/lib/annual_report/type_distribution_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe AnnualReport::TypeDistribution do - describe '#generate' do - subject { described_class.new(account, Time.zone.now.year) } - - context 'with an inactive account' do - let(:account) { Fabricate :account } - - it 'builds a report for an account' do - expect(subject.generate) - .to include( - type_distribution: include( - total: 0, - reblogs: 0, - replies: 0, - standalone: 0 - ) - ) - end - end - - context 'with an active account' do - let(:account) { Fabricate :account } - - before do - _other = Fabricate :status - Fabricate :status, reblog: Fabricate(:status), account: account - Fabricate :status, in_reply_to_id: Fabricate(:status).id, account: account, reply: true - Fabricate :status, account: account - end - - it 'builds a report for an account' do - expect(subject.generate) - .to include( - type_distribution: include( - total: 3, - reblogs: 1, - replies: 1, - standalone: 1 - ) - ) - end - end - end -end diff --git a/yarn.lock b/yarn.lock index 4534183654..0765267468 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,10 +12,10 @@ __metadata: languageName: node linkType: hard -"@acemir/cssom@npm:^0.9.19": - version: 0.9.19 - resolution: "@acemir/cssom@npm:0.9.19" - checksum: 10c0/baef216086b4c6d32ac02fff6621e5343969710d8262be3a84494564754424f60d3add8313c05a76465310e02bf72faa65abcb9febee15c2dc01d9b08c044d5a +"@acemir/cssom@npm:^0.9.23": + version: 0.9.24 + resolution: "@acemir/cssom@npm:0.9.24" + checksum: 10c0/1c7bf8a61a74d9ecbc3b12fba697384461b3234441ed5a10f5c34aef91fdf4f1e3322fcd6659a8eaddd591eddc2259efd278212236100d90a6e16f77794d98bd languageName: node linkType: hard @@ -59,16 +59,16 @@ __metadata: languageName: node linkType: hard -"@asamuzakjp/dom-selector@npm:^6.7.3": - version: 6.7.3 - resolution: "@asamuzakjp/dom-selector@npm:6.7.3" +"@asamuzakjp/dom-selector@npm:^6.7.4": + version: 6.7.5 + resolution: "@asamuzakjp/dom-selector@npm:6.7.5" dependencies: "@asamuzakjp/nwsapi": "npm:^2.3.9" bidi-js: "npm:^1.0.3" css-tree: "npm:^3.1.0" is-potential-custom-element-name: "npm:^1.0.1" lru-cache: "npm:^11.2.2" - checksum: 10c0/14af5b239e7c28db9a0378316da8b40669b29287c17a25119e34aa0b24336f7ed2b9b76b4fcf50c5221ffa0c6800d19ba3f5fa422786e3495af2dd64767cf741 + checksum: 10c0/72ac4dc45aac9165222345aacc1db51a84094f159e9e2fa71bc89befd2d78fd00a76c7ff9a8a1ceb60e7ce198a4ec0275a4d878bea67b756cadbf3d9680162c4 languageName: node linkType: hard @@ -4496,140 +4496,139 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:8.46.3": - version: 8.46.3 - resolution: "@typescript-eslint/eslint-plugin@npm:8.46.3" +"@typescript-eslint/eslint-plugin@npm:8.48.1": + version: 8.48.1 + resolution: "@typescript-eslint/eslint-plugin@npm:8.48.1" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:8.46.3" - "@typescript-eslint/type-utils": "npm:8.46.3" - "@typescript-eslint/utils": "npm:8.46.3" - "@typescript-eslint/visitor-keys": "npm:8.46.3" + "@typescript-eslint/scope-manager": "npm:8.48.1" + "@typescript-eslint/type-utils": "npm:8.48.1" + "@typescript-eslint/utils": "npm:8.48.1" + "@typescript-eslint/visitor-keys": "npm:8.48.1" graphemer: "npm:^1.4.0" ignore: "npm:^7.0.0" natural-compare: "npm:^1.4.0" ts-api-utils: "npm:^2.1.0" peerDependencies: - "@typescript-eslint/parser": ^8.46.3 + "@typescript-eslint/parser": ^8.48.1 eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/9c8a5efd9779418d2096634a072a9e2b108e146d0fc541572db56ff28ff37469f03dd404fdb3b0c3161be4cc4857ce14259f30eba1a93d4771de5d1562624e45 + checksum: 10c0/aeb4692ac27ded73dce5ddba08d46f15d617651f629cdfc5e874dd4ac767eac0523807f1f4e51f6f80675efff78e5937690f1c58740b8cb92b44b87d757a6a1a languageName: node linkType: hard -"@typescript-eslint/parser@npm:8.46.3": - version: 8.46.3 - resolution: "@typescript-eslint/parser@npm:8.46.3" +"@typescript-eslint/parser@npm:8.48.1": + version: 8.48.1 + resolution: "@typescript-eslint/parser@npm:8.48.1" dependencies: - "@typescript-eslint/scope-manager": "npm:8.46.3" - "@typescript-eslint/types": "npm:8.46.3" - "@typescript-eslint/typescript-estree": "npm:8.46.3" - "@typescript-eslint/visitor-keys": "npm:8.46.3" + "@typescript-eslint/scope-manager": "npm:8.48.1" + "@typescript-eslint/types": "npm:8.48.1" + "@typescript-eslint/typescript-estree": "npm:8.48.1" + "@typescript-eslint/visitor-keys": "npm:8.48.1" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/8a8b47abbbc8bbc68f423df23189afefd296305d50a31c6bec9bdde563adc9ddf99b89a6b8466965fda4aee9118263bae36422dd1c25d7595dd82f8897b5df61 + checksum: 10c0/54ec22c82cc631f56131bfed9747f8cadf52ab123463a406c5221f258f9533431c4a33ebe21ef178840d50235e69bb370d36aa2fd6a066e7223b38bfa41a1788 languageName: node linkType: hard -"@typescript-eslint/project-service@npm:8.46.3": - version: 8.46.3 - resolution: "@typescript-eslint/project-service@npm:8.46.3" +"@typescript-eslint/project-service@npm:8.48.1": + version: 8.48.1 + resolution: "@typescript-eslint/project-service@npm:8.48.1" dependencies: - "@typescript-eslint/tsconfig-utils": "npm:^8.46.3" - "@typescript-eslint/types": "npm:^8.46.3" + "@typescript-eslint/tsconfig-utils": "npm:^8.48.1" + "@typescript-eslint/types": "npm:^8.48.1" debug: "npm:^4.3.4" peerDependencies: typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/24ef305bbb550a8e27a7d6377663c1f2773b39b7a9f12c8b95c66c0d15f8150787b036bbff9ae4c2a0a18ab68c62435b0e03889df294bef00b3ae8846cd20659 + checksum: 10c0/0aeeea5e65d0f837bd9a47265f144f14ca72969d259ee929e63e06526b21f4e990e70c7bafdb2ceb3783373df7d9f5bae32c328a4c6403606f01339bc984b3f5 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.46.3": - version: 8.46.3 - resolution: "@typescript-eslint/scope-manager@npm:8.46.3" +"@typescript-eslint/scope-manager@npm:8.48.1": + version: 8.48.1 + resolution: "@typescript-eslint/scope-manager@npm:8.48.1" dependencies: - "@typescript-eslint/types": "npm:8.46.3" - "@typescript-eslint/visitor-keys": "npm:8.46.3" - checksum: 10c0/de8c116477e2a05a895ecd848a8289974a76cab884e07683c8085b3a2ce53895871d9bcd9de94723d6b2a437a6c526c77afcc75d6030cc4f1dccb9b47f4fc069 + "@typescript-eslint/types": "npm:8.48.1" + "@typescript-eslint/visitor-keys": "npm:8.48.1" + checksum: 10c0/16514823784cb598817b87d3d2b4fb618ab8b2378b3401a4c1160a5c914e51e7a925c3c1e7be73e0250e38390f0be70fecb3e0e0bdde7b243d74444933b95d3e languageName: node linkType: hard -"@typescript-eslint/tsconfig-utils@npm:8.46.3, @typescript-eslint/tsconfig-utils@npm:^8.46.3": - version: 8.46.3 - resolution: "@typescript-eslint/tsconfig-utils@npm:8.46.3" +"@typescript-eslint/tsconfig-utils@npm:8.48.1, @typescript-eslint/tsconfig-utils@npm:^8.48.1": + version: 8.48.1 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.48.1" peerDependencies: typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/a9686141204a96591ee51814a79fa676a8da845638eabb2363f9d82902660fd48ea47f7ec15a618129e45021ad154e1d193127248915752546d60d475d6a566e + checksum: 10c0/0d540f7ab3018ed1bab8f008c0d30229e0ea12806fdbf1c756572b5cf536a1f2a6c59ca2544c09bcd5b89dcfcf79e5f6be3d765e725492b9c7e4cd64fcecffc6 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:8.46.3": - version: 8.46.3 - resolution: "@typescript-eslint/type-utils@npm:8.46.3" +"@typescript-eslint/type-utils@npm:8.48.1": + version: 8.48.1 + resolution: "@typescript-eslint/type-utils@npm:8.48.1" dependencies: - "@typescript-eslint/types": "npm:8.46.3" - "@typescript-eslint/typescript-estree": "npm:8.46.3" - "@typescript-eslint/utils": "npm:8.46.3" + "@typescript-eslint/types": "npm:8.48.1" + "@typescript-eslint/typescript-estree": "npm:8.48.1" + "@typescript-eslint/utils": "npm:8.48.1" debug: "npm:^4.3.4" ts-api-utils: "npm:^2.1.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/06e20dff5a22feb6581703e8d35159ad6694d9e1df8fbb75869fcd89893826ca533b7b30b795a16d532e9d8ea6720462b1361d1e7a11d431a4cd11b3f47a22b5 + checksum: 10c0/c98a71f7d374be249ecc7c9f20b0a867a73ad4f64e646a6bf9f2c1a5d74f0dc7bd59e9c94a0842068caa366af39ae0c550ede6d653b5c9418a0a587510bbb6d5 languageName: node linkType: hard -"@typescript-eslint/types@npm:8.46.3, @typescript-eslint/types@npm:^8.46.0, @typescript-eslint/types@npm:^8.46.3": - version: 8.46.3 - resolution: "@typescript-eslint/types@npm:8.46.3" - checksum: 10c0/6a6ccefbd086e6c38172fe14d04ba27c1c34755af7c25e752547c42d978b91bf6b97da56a5e63d098fbd679b4a5076c4dd4be6c947fd39b4c5feea5fed6deeb6 +"@typescript-eslint/types@npm:8.48.1, @typescript-eslint/types@npm:^8.46.0, @typescript-eslint/types@npm:^8.48.1": + version: 8.48.1 + resolution: "@typescript-eslint/types@npm:8.48.1" + checksum: 10c0/366b8140f4c69319f1796b66b33c0c6e16eb6cbe543b9517003104e12ed143b620c1433ccf60d781a629d9433bd509a363c0c9d21fd438c17bb8840733af6caa languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.46.3": - version: 8.46.3 - resolution: "@typescript-eslint/typescript-estree@npm:8.46.3" +"@typescript-eslint/typescript-estree@npm:8.48.1": + version: 8.48.1 + resolution: "@typescript-eslint/typescript-estree@npm:8.48.1" dependencies: - "@typescript-eslint/project-service": "npm:8.46.3" - "@typescript-eslint/tsconfig-utils": "npm:8.46.3" - "@typescript-eslint/types": "npm:8.46.3" - "@typescript-eslint/visitor-keys": "npm:8.46.3" + "@typescript-eslint/project-service": "npm:8.48.1" + "@typescript-eslint/tsconfig-utils": "npm:8.48.1" + "@typescript-eslint/types": "npm:8.48.1" + "@typescript-eslint/visitor-keys": "npm:8.48.1" debug: "npm:^4.3.4" - fast-glob: "npm:^3.3.2" - is-glob: "npm:^4.0.3" minimatch: "npm:^9.0.4" semver: "npm:^7.6.0" + tinyglobby: "npm:^0.2.15" ts-api-utils: "npm:^2.1.0" peerDependencies: typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/3a2bb879a3b42eda478015beee42729efdc78c0cfc70fa009442706626813114f8f9a1e918638ab957df385681ab073cf2076c508973ff9a72e2425e4e521b4f + checksum: 10c0/72c0802f74222160f6a13ebbd32b0d504142a2427678c87ea78fc32672c65fd522377d43b31a97c944cbd0aefc36b320bf02f04e47c44f2797d6ccd0a8aa30ec languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.46.3, @typescript-eslint/utils@npm:^8.27.0, @typescript-eslint/utils@npm:^8.8.1": - version: 8.46.3 - resolution: "@typescript-eslint/utils@npm:8.46.3" +"@typescript-eslint/utils@npm:8.48.1, @typescript-eslint/utils@npm:^8.27.0, @typescript-eslint/utils@npm:^8.8.1": + version: 8.48.1 + resolution: "@typescript-eslint/utils@npm:8.48.1" dependencies: "@eslint-community/eslint-utils": "npm:^4.7.0" - "@typescript-eslint/scope-manager": "npm:8.46.3" - "@typescript-eslint/types": "npm:8.46.3" - "@typescript-eslint/typescript-estree": "npm:8.46.3" + "@typescript-eslint/scope-manager": "npm:8.48.1" + "@typescript-eslint/types": "npm:8.48.1" + "@typescript-eslint/typescript-estree": "npm:8.48.1" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/cf85b166f75c2fd248004fb59643315347489d9ab589738cda1b4c36c25e7947c197a1c21e46cb25959be7d0f310b352c4436f8d3e0a91d64e4fafb3ef4b4e3d + checksum: 10c0/1775ac217b578f52d6c1e85258098f8ef764d04830c6ce11043b434860da80f1a5f7cc1b9f2e0a63de161e83b8d876f7ae8362d7644d5d8e636e60ad5eeff4e2 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.46.3": - version: 8.46.3 - resolution: "@typescript-eslint/visitor-keys@npm:8.46.3" +"@typescript-eslint/visitor-keys@npm:8.48.1": + version: 8.48.1 + resolution: "@typescript-eslint/visitor-keys@npm:8.48.1" dependencies: - "@typescript-eslint/types": "npm:8.46.3" + "@typescript-eslint/types": "npm:8.48.1" eslint-visitor-keys: "npm:^4.2.1" - checksum: 10c0/c5f96840e0c31541e1a2390712a6cb290eff59fc97a3ffa7ecab353d3bb3cf0d8c6f62d68db271bf194aa8c4582be735b6121fcc5b30449e01799642be77de6e + checksum: 10c0/ecf4078ce63c296dd340672b516f42bf452534c75af7e7d6c1a3f32b143ff184cb3a4071d7429a9f870371ff9091a790acce28b85ce3c450bfc60554c79d43ca languageName: node linkType: hard @@ -6233,14 +6232,14 @@ __metadata: languageName: node linkType: hard -"cssstyle@npm:^5.3.2": - version: 5.3.2 - resolution: "cssstyle@npm:5.3.2" +"cssstyle@npm:^5.3.3": + version: 5.3.3 + resolution: "cssstyle@npm:5.3.3" dependencies: "@asamuzakjp/css-color": "npm:^4.0.3" "@csstools/css-syntax-patches-for-csstree": "npm:^1.0.14" css-tree: "npm:^3.1.0" - checksum: 10c0/513f0bd5d80fa91beadd24a9f4d4705f1f7e783acd90049ba6ceaf452101326208dd0d1d088d3565c4df94e4730582bf3857ea0fd3e733d10b6141be6eb68e40 + checksum: 10c0/0e082992851a1ded3662bda420f86dc1c90510a21cf237ddf573a1e121a722a3f78bb8f6eb46b33f267da25162e8e1fe968f7002114c9ab1d0d4e11dad9c5ee8 languageName: node linkType: hard @@ -7078,8 +7077,8 @@ __metadata: linkType: hard "eslint-plugin-jsdoc@npm:^61.1.11": - version: 61.1.12 - resolution: "eslint-plugin-jsdoc@npm:61.1.12" + version: 61.4.1 + resolution: "eslint-plugin-jsdoc@npm:61.4.1" dependencies: "@es-joy/jsdoccomment": "npm:~0.76.0" "@es-joy/resolve.exports": "npm:1.2.0" @@ -7097,7 +7096,7 @@ __metadata: to-valid-identifier: "npm:^1.0.0" peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - checksum: 10c0/a0d291796029f8c3711ece955afde3cbac2b366735ad99f22723e4d53e54b9dcb6224a7a23369d9bf95a25c01e64b7cf6e7807218b73a18fd33bfe6eabf0bbdd + checksum: 10c0/564f89bad71dcdbf6a45c27d16113333a5251f97a60bcc0e7346ea1b19dc1258991e1f585c89a2978e279288be2e180dde58c57f63cd49ac3db6604a5d4c581c languageName: node linkType: hard @@ -7181,14 +7180,14 @@ __metadata: linkType: hard "eslint-plugin-storybook@npm:^10.0.2": - version: 10.0.4 - resolution: "eslint-plugin-storybook@npm:10.0.4" + version: 10.1.4 + resolution: "eslint-plugin-storybook@npm:10.1.4" dependencies: "@typescript-eslint/utils": "npm:^8.8.1" peerDependencies: eslint: ">=8" - storybook: ^10.0.4 - checksum: 10c0/a2d486a6e45d1ce731333c439b51fc44b4a9292e8c0bca914534dab11cd37a3c25c62e8cbb1bb3b35e5e8b87d6ff2c7d8256c4f89a34c444138c4c738c52e1fc + storybook: ^10.1.4 + checksum: 10c0/d68a0244318a386877de12d22ce309725f9f7057002f5182fa50fc965e26ced7d051432d7495046f13ee5803634ce53ef9e58cfe2866c3251f2ff94f8ab50e74 languageName: node linkType: hard @@ -7426,7 +7425,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.2, fast-glob@npm:^3.3.3": +"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.3": version: 3.3.3 resolution: "fast-glob@npm:3.3.3" dependencies: @@ -8939,12 +8938,12 @@ __metadata: linkType: hard "jsdom@npm:^27.0.0": - version: 27.1.0 - resolution: "jsdom@npm:27.1.0" + version: 27.2.0 + resolution: "jsdom@npm:27.2.0" dependencies: - "@acemir/cssom": "npm:^0.9.19" - "@asamuzakjp/dom-selector": "npm:^6.7.3" - cssstyle: "npm:^5.3.2" + "@acemir/cssom": "npm:^0.9.23" + "@asamuzakjp/dom-selector": "npm:^6.7.4" + cssstyle: "npm:^5.3.3" data-urls: "npm:^6.0.0" decimal.js: "npm:^10.6.0" html-encoding-sniffer: "npm:^4.0.0" @@ -8967,7 +8966,7 @@ __metadata: peerDependenciesMeta: canvas: optional: true - checksum: 10c0/b3da39ab7c858df28a2300362924925327f5bff5727371523b99cac7f51bc2891c4b8516205c9acbd34430819f7e69f7790a2092a965359ed65d8111b3a79507 + checksum: 10c0/52d847e1aef099071d66d1d9aedcdd2f15e7ea781da9cfb41dc0d4caf741c5870c346396f8d1182d611427ae47a53f69a6f16410c698950e5809d3fed5a1672d languageName: node linkType: hard @@ -13611,17 +13610,17 @@ __metadata: linkType: hard "typescript-eslint@npm:^8.28.0, typescript-eslint@npm:^8.45.0": - version: 8.46.3 - resolution: "typescript-eslint@npm:8.46.3" + version: 8.48.1 + resolution: "typescript-eslint@npm:8.48.1" dependencies: - "@typescript-eslint/eslint-plugin": "npm:8.46.3" - "@typescript-eslint/parser": "npm:8.46.3" - "@typescript-eslint/typescript-estree": "npm:8.46.3" - "@typescript-eslint/utils": "npm:8.46.3" + "@typescript-eslint/eslint-plugin": "npm:8.48.1" + "@typescript-eslint/parser": "npm:8.48.1" + "@typescript-eslint/typescript-estree": "npm:8.48.1" + "@typescript-eslint/utils": "npm:8.48.1" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/c6d9398b16429b614c96405caae018b7ea74df55abf5ba9248ca9d02327704d6e1c3bdd2e2f52cfb25c9e5465ad93d73e19ee7fc3afbb837a6aeeecdf02c979b + checksum: 10c0/10b501bf69b14edd09d652b33e4a5dfad0498f2943992a433006933e384cdc5815217b2990801796ddf946d2ef4971d9a16c98c7cfbba41f6aa31b245ad057ac languageName: node linkType: hard @@ -14055,8 +14054,8 @@ __metadata: linkType: hard "vite@npm:^6.0.0 || ^7.0.0, vite@npm:^7.1.1": - version: 7.2.4 - resolution: "vite@npm:7.2.4" + version: 7.2.6 + resolution: "vite@npm:7.2.6" dependencies: esbuild: "npm:^0.25.0" fdir: "npm:^6.5.0" @@ -14105,7 +14104,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/26aa0cad01d6e00f17c837b2a0587ab52f6bd0d0e64606b4220cfc58fa5fa76a4095ef3ea27c886bea542a346363912c4fad9f9462ef1e6757262fedfd5196b2 + checksum: 10c0/d444a159ab8f0f854d596d1938f201b449d59ed4d336e587be9dc89005467214d85848c212c2495f76a8421372ffe4d061d023d659600f1aaa3ba5ac13e804f7 languageName: node linkType: hard