Merge commit 'dbb20f76a781defe35d077529c8269d712c1fbd2' into glitch-soc/merge-upstream
Conflicts: - `tsconfig.json`: glitch-soc had extra paths under `app/javascript/flavours`, but upstream added `app/javascript` as a whole, so updated to upstream's.
This commit is contained in:
commit
c9a1e27a49
91 files changed
+1108
-311
No files matched your search
@@ -1,6 +1,6 @@
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
import { render, fireEvent, screen } from 'mastodon/test_helpers';
|
||||
import { render, fireEvent, screen } from '@/testing/rendering';
|
||||
|
||||
import { Button } from '../button';
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||
|
||||
import { accountFactoryState, relationshipsFactory } from '@/testing/factories';
|
||||
|
||||
import { Account } from './index';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Account',
|
||||
component: Account,
|
||||
argTypes: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: 'ID of the account to display',
|
||||
},
|
||||
size: {
|
||||
type: 'number',
|
||||
description: 'Size of the avatar in pixels',
|
||||
},
|
||||
hidden: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the account is hidden or not',
|
||||
},
|
||||
minimal: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to display a minimal version of the account',
|
||||
},
|
||||
defaultAction: {
|
||||
type: 'string',
|
||||
control: 'select',
|
||||
options: ['block', 'mute'],
|
||||
description: 'Default action to take on the account',
|
||||
},
|
||||
withBio: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to display the account bio or not',
|
||||
},
|
||||
withMenu: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to display the account menu or not',
|
||||
},
|
||||
},
|
||||
args: {
|
||||
id: '1',
|
||||
size: 46,
|
||||
hidden: false,
|
||||
minimal: false,
|
||||
defaultAction: 'mute',
|
||||
withBio: false,
|
||||
withMenu: true,
|
||||
},
|
||||
parameters: {
|
||||
state: {
|
||||
accounts: {
|
||||
'1': accountFactoryState(),
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies Meta<typeof Account>;
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Primary: Story = {
|
||||
args: {
|
||||
id: '1',
|
||||
},
|
||||
};
|
||||
|
||||
export const Hidden: Story = {
|
||||
args: {
|
||||
hidden: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Minimal: Story = {
|
||||
args: {
|
||||
minimal: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithBio: Story = {
|
||||
args: {
|
||||
withBio: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const NoMenu: Story = {
|
||||
args: {
|
||||
withMenu: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const Blocked: Story = {
|
||||
args: {
|
||||
defaultAction: 'block',
|
||||
},
|
||||
parameters: {
|
||||
state: {
|
||||
relationships: {
|
||||
'1': relationshipsFactory({
|
||||
blocking: true,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Muted: Story = {
|
||||
args: {},
|
||||
parameters: {
|
||||
state: {
|
||||
relationships: {
|
||||
'1': relationshipsFactory({
|
||||
muting: true,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
File renamed without changes.
@@ -18,6 +18,7 @@ import initialState, { title as siteTitle } from 'mastodon/initial_state';
|
||||
import { IntlProvider } from 'mastodon/locales';
|
||||
import { store } from 'mastodon/store';
|
||||
import { isProduction } from 'mastodon/utils/environment';
|
||||
import { BodyScrollLock } from 'mastodon/features/ui/components/body_scroll_lock';
|
||||
|
||||
const title = isProduction() ? siteTitle : `${siteTitle} (Dev)`;
|
||||
|
||||
@@ -58,6 +59,7 @@ export default class Mastodon extends PureComponent {
|
||||
<ScrollContext shouldUpdateScroll={this.shouldUpdateScroll}>
|
||||
<Route path='/' component={UI} />
|
||||
</ScrollContext>
|
||||
<BodyScrollLock />
|
||||
</Router>
|
||||
|
||||
<Helmet defaultTitle={title} titleTemplate={`%s - ${title}`} />
|
||||
|
||||
@@ -14,7 +14,6 @@ import MediaModal from 'mastodon/features/ui/components/media_modal';
|
||||
import { Video } from 'mastodon/features/video';
|
||||
import { IntlProvider } from 'mastodon/locales';
|
||||
import { createPollFromServerJSON } from 'mastodon/models/poll';
|
||||
import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
|
||||
|
||||
const MEDIA_COMPONENTS = { MediaGallery, Video, Card, Poll, Hashtag, Audio };
|
||||
|
||||
@@ -34,9 +33,6 @@ export default class MediaContainer extends PureComponent {
|
||||
};
|
||||
|
||||
handleOpenMedia = (media, index, lang) => {
|
||||
document.body.classList.add('with-modals--active');
|
||||
document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
|
||||
|
||||
this.setState({ media, index, lang });
|
||||
};
|
||||
|
||||
@@ -45,16 +41,10 @@ export default class MediaContainer extends PureComponent {
|
||||
const { media } = JSON.parse(components[options.componentIndex].getAttribute('data-props'));
|
||||
const mediaList = fromJS(media);
|
||||
|
||||
document.body.classList.add('with-modals--active');
|
||||
document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
|
||||
|
||||
this.setState({ media: mediaList, lang, options });
|
||||
};
|
||||
|
||||
handleCloseMedia = () => {
|
||||
document.body.classList.remove('with-modals--active');
|
||||
document.documentElement.style.marginRight = '0';
|
||||
|
||||
this.setState({
|
||||
media: null,
|
||||
index: null,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { render, fireEvent, screen } from 'mastodon/test_helpers';
|
||||
import { render, fireEvent, screen } from '@/testing/rendering';
|
||||
|
||||
import Column from '../column';
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import { useLayoutEffect, useEffect, useState } from 'react';
|
||||
|
||||
import { createAppSelector, useAppSelector } from 'mastodon/store';
|
||||
import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
|
||||
|
||||
const getShouldLockBodyScroll = createAppSelector(
|
||||
[
|
||||
(state) => state.navigation.open,
|
||||
(state) => state.modal.get('stack').size > 0,
|
||||
],
|
||||
(isMobileMenuOpen: boolean, isModalOpen: boolean) => {
|
||||
return isMobileMenuOpen || isModalOpen;
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* This component locks scrolling on the `body` element when
|
||||
* `getShouldLockBodyScroll` returns true.
|
||||
*
|
||||
* The scrollbar width is taken into account and written to
|
||||
* a CSS custom property `--root-scrollbar-width`
|
||||
*/
|
||||
|
||||
export const BodyScrollLock: React.FC = () => {
|
||||
const shouldLockBodyScroll = useAppSelector(getShouldLockBodyScroll);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
document.body.classList.toggle('with-modals--active', shouldLockBodyScroll);
|
||||
}, [shouldLockBodyScroll]);
|
||||
|
||||
const [scrollbarWidth, setScrollbarWidth] = useState(() =>
|
||||
getScrollbarWidth(),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
setScrollbarWidth(getScrollbarWidth());
|
||||
};
|
||||
window.addEventListener('resize', handleResize, { passive: true });
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Inject style element to make scrollbar width available
|
||||
// as CSS custom property
|
||||
useLayoutEffect(() => {
|
||||
const nonce = document
|
||||
.querySelector('meta[name=style-nonce]')
|
||||
?.getAttribute('content');
|
||||
|
||||
if (nonce) {
|
||||
const styleEl = document.createElement('style');
|
||||
styleEl.nonce = nonce;
|
||||
styleEl.innerHTML = `
|
||||
:root {
|
||||
--root-scrollbar-width: ${scrollbarWidth}px;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(styleEl);
|
||||
|
||||
return () => {
|
||||
document.head.removeChild(styleEl);
|
||||
};
|
||||
}
|
||||
|
||||
return () => '';
|
||||
}, [scrollbarWidth]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
IgnoreNotificationsModal,
|
||||
AnnualReportModal,
|
||||
} from 'mastodon/features/ui/util/async-components';
|
||||
import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
|
||||
|
||||
import BundleContainer from '../containers/bundle_container';
|
||||
|
||||
@@ -90,20 +89,6 @@ export default class ModalRoot extends PureComponent {
|
||||
backgroundColor: null,
|
||||
};
|
||||
|
||||
getSnapshotBeforeUpdate () {
|
||||
return { visible: !!this.props.type };
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps, prevState, { visible }) {
|
||||
if (visible) {
|
||||
document.body.classList.add('with-modals--active');
|
||||
document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
|
||||
} else {
|
||||
document.body.classList.remove('with-modals--active');
|
||||
document.documentElement.style.marginRight = '0';
|
||||
}
|
||||
}
|
||||
|
||||
setBackgroundColor = color => {
|
||||
this.setState({ backgroundColor: color });
|
||||
};
|
||||
|
||||
@@ -804,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Porušení pravidla",
|
||||
"report_notification.categories.violation_sentence": "porušení pravidel",
|
||||
"report_notification.open": "Otevřít hlášení",
|
||||
"search.clear": "Vymazat hledání",
|
||||
"search.no_recent_searches": "Žádná nedávná vyhledávání",
|
||||
"search.placeholder": "Hledat",
|
||||
"search.quick_action.account_search": "Profily odpovídající {x}",
|
||||
|
||||
@@ -804,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Regelverstoß",
|
||||
"report_notification.categories.violation_sentence": "Regelverletzung",
|
||||
"report_notification.open": "Meldung öffnen",
|
||||
"search.clear": "Suchanfrage löschen",
|
||||
"search.no_recent_searches": "Keine früheren Suchanfragen",
|
||||
"search.placeholder": "Suchen",
|
||||
"search.quick_action.account_search": "Profile passend zu {x}",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"about.blocks": "Reguligitaj serviloj",
|
||||
"about.contact": "Kontakto:",
|
||||
"about.default_locale": "기본",
|
||||
"about.disclaimer": "Mastodon estas libera, malfermitkoda programo kaj varmarko de la firmao Mastodon gGmbH.",
|
||||
"about.domain_blocks.no_reason_available": "Kialo ne disponeblas",
|
||||
"about.domain_blocks.preamble": "Mastodon ĝenerale rajtigas vidi la enhavojn de uzantoj el aliaj serviloj en la fediverso, kaj komuniki kun ili. Jen la limigoj deciditaj de tiu ĉi servilo mem.",
|
||||
@@ -8,6 +9,7 @@
|
||||
"about.domain_blocks.silenced.title": "Limigita",
|
||||
"about.domain_blocks.suspended.explanation": "Neniuj datumoj el tiu servilo estos prilaboritaj, konservitaj, aŭ interŝanĝitaj, do neeblas interagi aŭ komuniki kun uzantoj de tiu servilo.",
|
||||
"about.domain_blocks.suspended.title": "Suspendita",
|
||||
"about.language_label": "Lingvo",
|
||||
"about.not_available": "Ĉi tiu informo ne estas disponebla ĉe ĉi tiu servilo.",
|
||||
"about.powered_by": "Malcentrigita socia retejo pere de {mastodon}",
|
||||
"about.rules": "Reguloj de la servilo",
|
||||
@@ -328,9 +330,13 @@
|
||||
"errors.unexpected_crash.copy_stacktrace": "Kopii stakspuron en tondujo",
|
||||
"errors.unexpected_crash.report_issue": "Raporti problemon",
|
||||
"explore.suggested_follows": "Homoj",
|
||||
"explore.title": "Popularaĵoj",
|
||||
"explore.trending_links": "Novaĵoj",
|
||||
"explore.trending_statuses": "Afiŝoj",
|
||||
"explore.trending_tags": "Kradvortoj",
|
||||
"featured_carousel.next": "Antaŭen",
|
||||
"featured_carousel.post": "Afiŝi",
|
||||
"featured_carousel.previous": "Malantaŭen",
|
||||
"filter_modal.added.context_mismatch_explanation": "Ĉi tiu filtrilkategorio ne kongruas kun la kunteksto en kiu vi akcesis ĉi tiun afiŝon. Se vi volas ke la afiŝo estas ankaŭ filtrita en ĉi tiu kunteksto, vi devus redakti la filtrilon.",
|
||||
"filter_modal.added.context_mismatch_title": "Ne kongruas la kunteksto!",
|
||||
"filter_modal.added.expired_explanation": "Ĉi tiu filtrilkategorio eksvalidiĝis, vu bezonos ŝanĝi la eksvaliddaton por ĝi.",
|
||||
@@ -547,6 +553,7 @@
|
||||
"navigation_bar.lists": "Listoj",
|
||||
"navigation_bar.logout": "Elsaluti",
|
||||
"navigation_bar.moderation": "Modereco",
|
||||
"navigation_bar.more": "Pli",
|
||||
"navigation_bar.mutes": "Silentigitaj uzantoj",
|
||||
"navigation_bar.opened_in_classic_interface": "Afiŝoj, kontoj, kaj aliaj specifaj paĝoj kiuj estas malfermititaj defaulta en la klasika reta interfaco.",
|
||||
"navigation_bar.preferences": "Preferoj",
|
||||
@@ -777,6 +784,7 @@
|
||||
"report_notification.categories.violation": "Malobservo de la regulo",
|
||||
"report_notification.categories.violation_sentence": "malobservo de la regulo",
|
||||
"report_notification.open": "Malfermi la raporton",
|
||||
"search.clear": "검색어 지우기",
|
||||
"search.no_recent_searches": "Neniuj lastaj serĉoj",
|
||||
"search.placeholder": "Serĉi",
|
||||
"search.quick_action.account_search": "Profiloj kiuj kongruas kun {x}",
|
||||
@@ -872,7 +880,9 @@
|
||||
"subscribed_languages.save": "Konservi ŝanĝojn",
|
||||
"subscribed_languages.target": "Ŝanĝu abonitajn lingvojn por {target}",
|
||||
"tabs_bar.home": "Hejmo",
|
||||
"tabs_bar.menu": "Menuo",
|
||||
"tabs_bar.notifications": "Sciigoj",
|
||||
"tabs_bar.search": "Serĉi",
|
||||
"terms_of_service.effective_as_of": "Ĝi ekvalidas de {date}",
|
||||
"terms_of_service.title": "Kondiĉoj de uzado",
|
||||
"terms_of_service.upcoming_changes_on": "Venontaj ŝanĝoj el {date}",
|
||||
|
||||
@@ -804,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Violación de regla",
|
||||
"report_notification.categories.violation_sentence": "violación de regla",
|
||||
"report_notification.open": "Abrir denuncia",
|
||||
"search.clear": "Limpiar búsqueda",
|
||||
"search.no_recent_searches": "Sin búsquedas recientes",
|
||||
"search.placeholder": "Buscar",
|
||||
"search.quick_action.account_search": "Perfiles que coinciden con {x}",
|
||||
|
||||
@@ -804,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Infracción de regla",
|
||||
"report_notification.categories.violation_sentence": "infracción de regla",
|
||||
"report_notification.open": "Abrir denuncia",
|
||||
"search.clear": "Limpiar búsqueda",
|
||||
"search.no_recent_searches": "Sin búsquedas recientes",
|
||||
"search.placeholder": "Buscar",
|
||||
"search.quick_action.account_search": "Perfiles que coinciden con {x}",
|
||||
|
||||
@@ -804,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Infracción de regla",
|
||||
"report_notification.categories.violation_sentence": "infracción de regla",
|
||||
"report_notification.open": "Abrir informe",
|
||||
"search.clear": "Limpiar búsqueda",
|
||||
"search.no_recent_searches": "No hay búsquedas recientes",
|
||||
"search.placeholder": "Buscar",
|
||||
"search.quick_action.account_search": "Perfiles que coinciden con {x}",
|
||||
|
||||
@@ -804,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Brotin regla",
|
||||
"report_notification.categories.violation_sentence": "brot á reglu",
|
||||
"report_notification.open": "Opna melding",
|
||||
"search.clear": "Nullstilla leiting",
|
||||
"search.no_recent_searches": "Ongar nýggjar leitingar",
|
||||
"search.placeholder": "Leita",
|
||||
"search.quick_action.account_search": "Vangar, ið samsvara {x}",
|
||||
|
||||
@@ -563,6 +563,8 @@
|
||||
"navigation_bar.follows_and_followers": "Seguindo e seguidoras",
|
||||
"navigation_bar.import_export": "Importar e exportar",
|
||||
"navigation_bar.lists": "Listaxes",
|
||||
"navigation_bar.live_feed_local": "En directo (local)",
|
||||
"navigation_bar.live_feed_public": "En directo (federada)",
|
||||
"navigation_bar.logout": "Pechar sesión",
|
||||
"navigation_bar.moderation": "Moderación",
|
||||
"navigation_bar.more": "Máis",
|
||||
@@ -802,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Faltou ás regras",
|
||||
"report_notification.categories.violation_sentence": "violación das regras",
|
||||
"report_notification.open": "Abrir a denuncia",
|
||||
"search.clear": "Limpar a busca",
|
||||
"search.no_recent_searches": "Non hai buscas recentes",
|
||||
"search.placeholder": "Procurar",
|
||||
"search.quick_action.account_search": "Perfís coincidentes {x}",
|
||||
|
||||
@@ -804,6 +804,7 @@
|
||||
"report_notification.categories.violation": "הפרת כלל",
|
||||
"report_notification.categories.violation_sentence": "הפרת כלל",
|
||||
"report_notification.open": "פתח דו\"ח",
|
||||
"search.clear": "ניקוי חיפוש",
|
||||
"search.no_recent_searches": "לא נמצאו חיפושים אחרונים",
|
||||
"search.placeholder": "חיפוש",
|
||||
"search.quick_action.account_search": "פרופילים המכילים {x}",
|
||||
|
||||
@@ -804,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Szabálysértés",
|
||||
"report_notification.categories.violation_sentence": "szabálysértés",
|
||||
"report_notification.open": "Bejelentés megnyitása",
|
||||
"search.clear": "Keresés törlése",
|
||||
"search.no_recent_searches": "Nincsenek keresési előzmények",
|
||||
"search.placeholder": "Keresés",
|
||||
"search.quick_action.account_search": "Profilok a következő keresésre: {x}",
|
||||
|
||||
@@ -563,6 +563,8 @@
|
||||
"navigation_bar.follows_and_followers": "팔로우와 팔로워",
|
||||
"navigation_bar.import_export": "가져오기 & 내보내기",
|
||||
"navigation_bar.lists": "리스트",
|
||||
"navigation_bar.live_feed_local": "라이브 피드 (로컬)",
|
||||
"navigation_bar.live_feed_public": "라이브 피드 (공개)",
|
||||
"navigation_bar.logout": "로그아웃",
|
||||
"navigation_bar.moderation": "중재",
|
||||
"navigation_bar.more": "더 보기",
|
||||
@@ -802,6 +804,7 @@
|
||||
"report_notification.categories.violation": "규칙 위반",
|
||||
"report_notification.categories.violation_sentence": "규칙 위반",
|
||||
"report_notification.open": "신고 열기",
|
||||
"search.clear": "검색 초기화",
|
||||
"search.no_recent_searches": "최근 검색 기록이 없습니다",
|
||||
"search.placeholder": "검색",
|
||||
"search.quick_action.account_search": "{x}에 맞는 프로필",
|
||||
|
||||
@@ -563,6 +563,8 @@
|
||||
"navigation_bar.follows_and_followers": "Volgers en gevolgde accounts",
|
||||
"navigation_bar.import_export": "Importeren en exporteren",
|
||||
"navigation_bar.lists": "Lijsten",
|
||||
"navigation_bar.live_feed_local": "Openbare tijdlijn (deze server)",
|
||||
"navigation_bar.live_feed_public": "Openbare tijdlijn (alles)",
|
||||
"navigation_bar.logout": "Uitloggen",
|
||||
"navigation_bar.moderation": "Moderatie",
|
||||
"navigation_bar.more": "Meer",
|
||||
@@ -802,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Overtreden regel(s)",
|
||||
"report_notification.categories.violation_sentence": "serverregel overtreden",
|
||||
"report_notification.open": "Rapportage openen",
|
||||
"search.clear": "Zoekopdracht wissen",
|
||||
"search.no_recent_searches": "Geen recente zoekopdrachten",
|
||||
"search.placeholder": "Zoeken",
|
||||
"search.quick_action.account_search": "Accounts die overeenkomen met {x}",
|
||||
|
||||
@@ -563,6 +563,8 @@
|
||||
"navigation_bar.follows_and_followers": "Seguindo e seguidores",
|
||||
"navigation_bar.import_export": "Importar e exportar",
|
||||
"navigation_bar.lists": "Listas",
|
||||
"navigation_bar.live_feed_local": "Cronologia local",
|
||||
"navigation_bar.live_feed_public": "Cronologia federada",
|
||||
"navigation_bar.logout": "Sair",
|
||||
"navigation_bar.moderation": "Moderação",
|
||||
"navigation_bar.more": "Mais",
|
||||
@@ -799,6 +801,7 @@
|
||||
"report_notification.categories.violation": "Violação de regra",
|
||||
"report_notification.categories.violation_sentence": "violação de regra",
|
||||
"report_notification.open": "Abrir denúncia",
|
||||
"search.clear": "Limpar pesquisa",
|
||||
"search.no_recent_searches": "Nenhuma pesquisa recente",
|
||||
"search.placeholder": "Pesquisar",
|
||||
"search.quick_action.account_search": "Perfis com correspondência a {x}",
|
||||
|
||||
@@ -563,6 +563,8 @@
|
||||
"navigation_bar.follows_and_followers": "Подписки и подписчики",
|
||||
"navigation_bar.import_export": "Импорт и экспорт",
|
||||
"navigation_bar.lists": "Списки",
|
||||
"navigation_bar.live_feed_local": "Живая лента (локальная)",
|
||||
"navigation_bar.live_feed_public": "Живая лента (глобальная)",
|
||||
"navigation_bar.logout": "Выйти",
|
||||
"navigation_bar.moderation": "Модерирование",
|
||||
"navigation_bar.more": "Ещё",
|
||||
@@ -578,9 +580,9 @@
|
||||
"navigation_panel.expand_lists": "Развернуть меню списков",
|
||||
"not_signed_in_indicator.not_signed_in": "Эта страница доступна только авторизованным пользователям.",
|
||||
"notification.admin.report": "{name} пожаловался (-лась) на {target}",
|
||||
"notification.admin.report_account": "{name} пожаловался (-лась) на {count, plural, one {# пост} few {# поста} other {# постов}} пользователя {target} по причине «{category}»",
|
||||
"notification.admin.report_account": "{name} пожаловался (-лась) на {count, plural, one {# пост} few {# поста} other {# постов}} пользователя {target}, выбрав категорию «{category}»",
|
||||
"notification.admin.report_account_other": "{name} пожаловался (-лась) на {count, plural, one {# пост} few {# поста} other {# постов}} пользователя {target}",
|
||||
"notification.admin.report_statuses": "{name} пожаловался (-лась) на {target} по причине «{category}»",
|
||||
"notification.admin.report_statuses": "{name} пожаловался (-лась) на {target}, выбрав категорию «{category}»",
|
||||
"notification.admin.report_statuses_other": "{name} пожаловался (-лась) на {target}",
|
||||
"notification.admin.sign_up": "{name} зарегистрировался (-лась) на сервере",
|
||||
"notification.admin.sign_up.name_and_others": "{name} и ещё {count, plural, one {# пользователь} few {# пользователя} other {# пользователей}} зарегистрировались на сервере",
|
||||
@@ -602,13 +604,13 @@
|
||||
"notification.mentioned_you": "{name} упомянул(а) вас",
|
||||
"notification.moderation-warning.learn_more": "Узнать больше",
|
||||
"notification.moderation_warning": "Модераторы вынесли вам предупреждение",
|
||||
"notification.moderation_warning.action_delete_statuses": "Некоторые из ваших публикаций были удалены.",
|
||||
"notification.moderation_warning.action_delete_statuses": "Некоторые ваши посты были удалены.",
|
||||
"notification.moderation_warning.action_disable": "Ваша учётная запись была отключена.",
|
||||
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Некоторые из ваших сообщений были отмечены как деликатные.",
|
||||
"notification.moderation_warning.action_none": "Ваша учётная запись получила предупреждение от модерации.",
|
||||
"notification.moderation_warning.action_sensitive": "С этого момента ваши сообщения будут помечены как деликатные.",
|
||||
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Некоторые ваши посты получили отметку деликатного содержания.",
|
||||
"notification.moderation_warning.action_none": "Модераторы вынесли вам предупреждение.",
|
||||
"notification.moderation_warning.action_sensitive": "С этого момента ваши посты будут иметь отметку деликатного содержания.",
|
||||
"notification.moderation_warning.action_silence": "Ваша учётная запись была ограничена.",
|
||||
"notification.moderation_warning.action_suspend": "Действие вашей учётной записи приостановлено.",
|
||||
"notification.moderation_warning.action_suspend": "Ваша учётная запись была заблокирована.",
|
||||
"notification.own_poll": "Ваш опрос завершился",
|
||||
"notification.poll": "Опрос, в котором вы приняли участие, завершился",
|
||||
"notification.reblog": "{name} продвинул(а) ваш пост",
|
||||
@@ -792,16 +794,17 @@
|
||||
"report.thanks.title_actionable": "Спасибо, что сообщили о проблеме, мы рассмотрим вашу жалобу.",
|
||||
"report.unfollow": "Отписаться от @{name}",
|
||||
"report.unfollow_explanation": "Вы подписаны на этого пользователя. Отпишитесь от пользователя, чтобы перестать видеть посты этого человека в домашней ленте.",
|
||||
"report_notification.attached_statuses": "{count, plural, one {{count} сообщение} few {{count} сообщения} many {{count} сообщений} other {{count} сообщений}} вложено",
|
||||
"report_notification.attached_statuses": "{count, plural, one {{count} пост прикреплён} few {{count} поста прикреплено} other {{count} постов прикреплено}}",
|
||||
"report_notification.categories.legal": "Нарушение закона",
|
||||
"report_notification.categories.legal_sentence": "запрещённый контент",
|
||||
"report_notification.categories.legal_sentence": "Нарушение закона",
|
||||
"report_notification.categories.other": "Другое",
|
||||
"report_notification.categories.other_sentence": "другое",
|
||||
"report_notification.categories.other_sentence": "Другое",
|
||||
"report_notification.categories.spam": "Спам",
|
||||
"report_notification.categories.spam_sentence": "спам",
|
||||
"report_notification.categories.spam_sentence": "Спам",
|
||||
"report_notification.categories.violation": "Нарушение правил",
|
||||
"report_notification.categories.violation_sentence": "нарушение правила",
|
||||
"report_notification.open": "Открыть жалобу",
|
||||
"report_notification.categories.violation_sentence": "Нарушение правил",
|
||||
"report_notification.open": "Перейти к жалобе",
|
||||
"search.clear": "Очистить поисковый запрос",
|
||||
"search.no_recent_searches": "Недавние запросы отсутствуют",
|
||||
"search.placeholder": "Поиск",
|
||||
"search.quick_action.account_search": "Профили, соответствующие {x}",
|
||||
@@ -868,6 +871,7 @@
|
||||
"status.mute_conversation": "Игнорировать обсуждение",
|
||||
"status.open": "Открыть пост",
|
||||
"status.pin": "Закрепить в профиле",
|
||||
"status.quote_error.filtered": "Скрыто одним из ваших фильтров",
|
||||
"status.quote_error.removed": "Этот пост был удалён его автором.",
|
||||
"status.read_more": "Читать далее",
|
||||
"status.reblog": "Продвинуть",
|
||||
|
||||
@@ -779,6 +779,7 @@
|
||||
"report_notification.categories.violation": "Порушення правил",
|
||||
"report_notification.categories.violation_sentence": "порушення правил",
|
||||
"report_notification.open": "Відкрити скаргу",
|
||||
"search.clear": "Очистити пошук",
|
||||
"search.no_recent_searches": "Немає останніх пошуків",
|
||||
"search.placeholder": "Пошук",
|
||||
"search.quick_action.account_search": "Збіг профілів {x}",
|
||||
|
||||
@@ -804,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Vi phạm nội quy",
|
||||
"report_notification.categories.violation_sentence": "vi phạm nội quy",
|
||||
"report_notification.open": "Mở báo cáo",
|
||||
"search.clear": "Xóa tìm kiếm",
|
||||
"search.no_recent_searches": "Gần đây chưa tìm gì",
|
||||
"search.placeholder": "Tìm kiếm",
|
||||
"search.quick_action.account_search": "Người tên {x}",
|
||||
|
||||
@@ -804,6 +804,7 @@
|
||||
"report_notification.categories.violation": "違反規則",
|
||||
"report_notification.categories.violation_sentence": "違反規則",
|
||||
"report_notification.open": "開啟檢舉報告",
|
||||
"search.clear": "清除搜尋紀錄",
|
||||
"search.no_recent_searches": "尚無最近的搜尋紀錄",
|
||||
"search.placeholder": "搜尋",
|
||||
"search.quick_action.account_search": "符合的個人檔案 {x}",
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { isMobile } from '../is_mobile';
|
||||
|
||||
let cachedScrollbarWidth: number | null = null;
|
||||
|
||||
const getActualScrollbarWidth = () => {
|
||||
export const getScrollbarWidth = () => {
|
||||
if (isMobile(window.innerWidth)) {
|
||||
return 0;
|
||||
}
|
||||
const outer = document.createElement('div');
|
||||
outer.style.visibility = 'hidden';
|
||||
outer.style.overflow = 'scroll';
|
||||
@@ -16,16 +17,3 @@ const getActualScrollbarWidth = () => {
|
||||
|
||||
return scrollbarWidth;
|
||||
};
|
||||
|
||||
export const getScrollbarWidth = () => {
|
||||
if (cachedScrollbarWidth !== null) {
|
||||
return cachedScrollbarWidth;
|
||||
}
|
||||
|
||||
const scrollbarWidth = isMobile(window.innerWidth)
|
||||
? 0
|
||||
: getActualScrollbarWidth();
|
||||
cachedScrollbarWidth = scrollbarWidth;
|
||||
|
||||
return scrollbarWidth;
|
||||
};
|
||||
@@ -1648,6 +1648,17 @@ a.sparkline {
|
||||
}
|
||||
}
|
||||
|
||||
a.timestamp {
|
||||
color: $darker-text-color;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
time {
|
||||
margin-inline-start: 5px;
|
||||
vertical-align: baseline;
|
||||
|
||||
@@ -68,6 +68,7 @@ body {
|
||||
&.with-modals--active {
|
||||
overflow-y: hidden;
|
||||
overscroll-behavior: none;
|
||||
margin-right: var(--root-scrollbar-width, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2894,6 +2894,11 @@ a.account__display-name {
|
||||
background: var(--background-color);
|
||||
backdrop-filter: var(--background-filter);
|
||||
border-top: 1px solid var(--background-border-color);
|
||||
box-sizing: border-box;
|
||||
|
||||
.with-modals--active & {
|
||||
padding-right: var(--root-scrollbar-width);
|
||||
}
|
||||
|
||||
.layout-multiple-columns & {
|
||||
display: none;
|
||||
@@ -3105,7 +3110,7 @@ a.account__display-name {
|
||||
.search__input {
|
||||
line-height: 18px;
|
||||
font-size: 16px;
|
||||
padding: 15px;
|
||||
padding-block: 15px;
|
||||
padding-inline-end: 30px;
|
||||
}
|
||||
|
||||
@@ -8972,7 +8977,7 @@ noscript {
|
||||
|
||||
.search__input {
|
||||
border: 1px solid var(--background-border-color);
|
||||
padding: 12px;
|
||||
padding-block: 12px;
|
||||
padding-inline-end: 30px;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import { action } from 'storybook/actions';
|
||||
|
||||
import { relationshipsFactory } from './factories';
|
||||
|
||||
export const mockHandlers = {
|
||||
mute: http.post<{ id: string }>('/api/v1/accounts/:id/mute', ({ params }) => {
|
||||
action('muting account')(params);
|
||||
return HttpResponse.json(
|
||||
relationshipsFactory({ id: params.id, muting: true }),
|
||||
);
|
||||
}),
|
||||
unmute: http.post<{ id: string }>(
|
||||
'/api/v1/accounts/:id/unmute',
|
||||
({ params }) => {
|
||||
action('unmuting account')(params);
|
||||
return HttpResponse.json(
|
||||
relationshipsFactory({ id: params.id, muting: false }),
|
||||
);
|
||||
},
|
||||
),
|
||||
block: http.post<{ id: string }>(
|
||||
'/api/v1/accounts/:id/block',
|
||||
({ params }) => {
|
||||
action('blocking account')(params);
|
||||
return HttpResponse.json(
|
||||
relationshipsFactory({ id: params.id, blocking: true }),
|
||||
);
|
||||
},
|
||||
),
|
||||
unblock: http.post<{ id: string }>(
|
||||
'/api/v1/accounts/:id/unblock',
|
||||
({ params }) => {
|
||||
action('unblocking account')(params);
|
||||
return HttpResponse.json(
|
||||
relationshipsFactory({
|
||||
id: params.id,
|
||||
blocking: false,
|
||||
}),
|
||||
);
|
||||
},
|
||||
),
|
||||
};
|
||||
|
||||
export const unhandledRequestHandler = ({ url }: Request) => {
|
||||
const { pathname } = new URL(url);
|
||||
if (pathname.startsWith('/api/v1/')) {
|
||||
action(`unhandled request to ${pathname}`)(url);
|
||||
console.warn(
|
||||
`Unhandled request to ${pathname}. Please add a handler for this request in your storybook configuration.`,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
import type { ApiRelationshipJSON } from '@/mastodon/api_types/relationships';
|
||||
import { createAccountFromServerJSON } from '@/mastodon/models/account';
|
||||
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
|
||||
|
||||
type FactoryOptions<T> = {
|
||||
id?: string;
|
||||
} & Partial<T>;
|
||||
|
||||
type FactoryFunction<T> = (options?: FactoryOptions<T>) => T;
|
||||
|
||||
export const accountFactory: FactoryFunction<ApiAccountJSON> = ({
|
||||
id,
|
||||
...data
|
||||
} = {}) => ({
|
||||
id: id ?? '1',
|
||||
acct: 'testuser',
|
||||
avatar: '/avatars/original/missing.png',
|
||||
avatar_static: '/avatars/original/missing.png',
|
||||
username: 'testuser',
|
||||
display_name: 'Test User',
|
||||
bot: false,
|
||||
created_at: '2023-01-01T00:00:00.000Z',
|
||||
discoverable: true,
|
||||
emojis: [],
|
||||
fields: [],
|
||||
followers_count: 0,
|
||||
following_count: 0,
|
||||
group: false,
|
||||
header: '/header.png',
|
||||
header_static: '/header_static.png',
|
||||
indexable: true,
|
||||
last_status_at: '2023-01-01',
|
||||
locked: false,
|
||||
mute_expires_at: null,
|
||||
note: 'This is a test user account.',
|
||||
statuses_count: 0,
|
||||
suspended: false,
|
||||
url: '/@testuser',
|
||||
uri: '/users/testuser',
|
||||
noindex: false,
|
||||
roles: [],
|
||||
hide_collections: false,
|
||||
...data,
|
||||
});
|
||||
|
||||
export const accountFactoryState = (
|
||||
options: FactoryOptions<ApiAccountJSON> = {},
|
||||
) => createAccountFromServerJSON(accountFactory(options));
|
||||
|
||||
export const relationshipsFactory: FactoryFunction<ApiRelationshipJSON> = ({
|
||||
id,
|
||||
...data
|
||||
} = {}) => ({
|
||||
id: id ?? '1',
|
||||
following: false,
|
||||
followed_by: false,
|
||||
blocking: false,
|
||||
blocked_by: false,
|
||||
languages: null,
|
||||
muting_notifications: false,
|
||||
note: '',
|
||||
requested_by: false,
|
||||
muting: false,
|
||||
requested: false,
|
||||
domain_blocking: false,
|
||||
endorsed: false,
|
||||
notifying: false,
|
||||
showing_reblogs: true,
|
||||
...data,
|
||||
});
|
||||
@@ -5,7 +5,7 @@ import { MemoryRouter } from 'react-router';
|
||||
import type { RenderOptions } from '@testing-library/react';
|
||||
import { render as rtlRender } from '@testing-library/react';
|
||||
|
||||
import { IdentityContext } from './identity_context';
|
||||
import { IdentityContext } from '@/mastodon/identity_context';
|
||||
|
||||
beforeAll(() => {
|
||||
global.requestIdleCallback = vi.fn((cb: IdleRequestCallback) => {
|
||||
Reference in new issue
Block a user