Merge commit '53be8392eceea8c3a576478e209fe82c2ceb458a' into glitch-soc/merge-upstream

This commit is contained in:
Claire committed 2025-12-16 18:27:03 +01:00
commit 780fefa700
45 files changed
+504 -208

No files matched your search

@@ -10,6 +10,7 @@ import classNames from 'classnames/bind';
import { closeModal } from '@/mastodon/actions/modal';
import { IconButton } from '@/mastodon/components/icon_button';
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
import { getReport } from '@/mastodon/reducers/slices/annual_report';
import {
createAppSelector,
useAppDispatch,
@@ -26,7 +27,7 @@ import { NewPosts } from './new_posts';
const moduleClassNames = classNames.bind(styles);
const accountSelector = createAppSelector(
export const accountSelector = createAppSelector(
[(state) => state.accounts, (state) => state.annualReport.report],
(accounts, report) => {
if (report?.schema_version === 2) {
@@ -43,6 +44,13 @@ export const AnnualReport: FC<{ context?: 'modal' | 'standalone' }> = ({
const dispatch = useAppDispatch();
const report = useAppSelector((state) => state.annualReport.report);
const account = useAppSelector(accountSelector);
const needsReport = !report; // Make into boolean to avoid object comparison in deps.
useEffect(() => {
if (needsReport) {
void dispatch(getReport());
}
}, [dispatch, needsReport]);
const close = useCallback(() => {
dispatch(closeModal({ modalType: 'ANNUAL_REPORT', ignoreFocus: false }));
@@ -57,7 +65,7 @@ export const AnnualReport: FC<{ context?: 'modal' | 'standalone' }> = ({
}
}, [pathname, initialPathname, close]);
if (!report) {
if (needsReport) {
return <LoadingIndicator />;
}
@@ -4,10 +4,7 @@ import { useCallback, useEffect } from 'react';
import classNames from 'classnames';
import { closeModal } from '@/mastodon/actions/modal';
import {
generateReport,
selectWrapstodonYear,
} from '@/mastodon/reducers/slices/annual_report';
import { generateReport } from '@/mastodon/reducers/slices/annual_report';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import { AnnualReport } from '.';
@@ -21,8 +18,7 @@ const AnnualReportModal: React.FC<{
onChangeBackgroundColor('var(--color-bg-media-base)');
}, [onChangeBackgroundColor]);
const { state } = useAppSelector((state) => state.annualReport);
const year = useAppSelector(selectWrapstodonYear);
const { state, year } = useAppSelector((state) => state.annualReport);
const showAnnouncement = year && state && state !== 'available';
@@ -8,7 +8,6 @@ import classNames from 'classnames';
import IconPlanet from '@/images/icons/icon_planet.svg?react';
import { openModal } from '@/mastodon/actions/modal';
import { Icon } from '@/mastodon/components/icon';
import { selectWrapstodonYear } from '@/mastodon/reducers/slices/annual_report';
import {
createAppSelector,
useAppDispatch,
@@ -23,8 +22,7 @@ const selectReportModalOpen = createAppSelector(
);
export const AnnualReportNavItem: FC = () => {
const { state } = useAppSelector((state) => state.annualReport);
const year = useAppSelector(selectWrapstodonYear);
const { state, year } = useAppSelector((state) => state.annualReport);
const active = useAppSelector(selectReportModalOpen);
const dispatch = useAppDispatch();
@@ -16,22 +16,16 @@ $mobile-breakpoint: 540px;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.75rem;
gap: 1.8rem;
margin-top: 2rem;
font-size: 16px;
line-height: 1.4;
text-align: center;
color: var(--color-text-secondary);
}
.logo {
width: 2rem;
opacity: 0.6;
}
.nav {
display: flex;
flex-wrap: wrap;
gap: 12px;
strong {
font-weight: 600;
}
a:any-link {
color: inherit;
@@ -43,3 +37,22 @@ $mobile-breakpoint: 540px;
color: var(--color-text-primary);
}
}
.logo {
width: 2rem;
opacity: 0.6;
}
.footerSection {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
.linkList {
list-style: none;
display: flex;
flex-wrap: wrap;
gap: 12px;
}
@@ -2,43 +2,66 @@ import type { FC } from 'react';
import { FormattedMessage } from 'react-intl';
import { DisplayName } from '@/mastodon/components/display_name';
import { IconLogo } from '@/mastodon/components/logo';
import { useAppSelector } from '@/mastodon/store';
import { AnnualReport } from './index';
import { AnnualReport, accountSelector } from './index';
import classes from './shared_page.module.scss';
export const WrapstodonSharedPage: FC = () => {
const isLoggedIn = useAppSelector((state) => !!state.meta.get('me'));
const account = useAppSelector(accountSelector);
const domain = useAppSelector((state) => state.meta.get('domain') as string);
return (
<main className={classes.wrapper}>
<AnnualReport />
<footer className={classes.footer}>
<IconLogo className={classes.logo} />
<FormattedMessage
id='annual_report.shared_page.footer'
defaultMessage='Generated with {heart} by the Mastodon team'
values={{ heart: '🐘' }}
/>
<nav className={classes.nav}>
<a href='https://joinmastodon.org'>
<FormattedMessage id='footer.about' defaultMessage='About' />
</a>
{!isLoggedIn && (
<a href='https://joinmastodon.org/servers'>
<FormattedMessage
id='annual_report.shared_page.sign_up'
defaultMessage='Sign up'
/>
</a>
)}
<a href='https://joinmastodon.org/sponsors'>
<div className={classes.footerSection}>
<IconLogo className={classes.logo} />
<FormattedMessage
id='annual_report.shared_page.footer'
defaultMessage='Generated with {heart} by the Mastodon team'
values={{ heart: '🐘' }}
tagName='p'
/>
<ul className={classes.linkList}>
<li>
<a href='https://joinmastodon.org'>
<FormattedMessage
id='footer.about_mastodon'
defaultMessage='About Mastodon'
/>
</a>
</li>
<li>
<a href='https://joinmastodon.org/sponsors'>
<FormattedMessage
id='annual_report.shared_page.donate'
defaultMessage='Donate'
/>
</a>
</li>
</ul>
</div>
<div className={classes.footerSection}>
<FormattedMessage
id='annual_report.shared_page.footer_server_info'
defaultMessage='{username} uses {domain}, one of many communities powered by Mastodon.'
values={{
username: <DisplayName variant='simple' account={account} />,
domain: <strong>{domain}</strong>,
}}
tagName='p'
/>
<a href='/about'>
<FormattedMessage
id='annual_report.shared_page.donate'
defaultMessage='Donate'
id='footer.about_server'
defaultMessage='About {domain}'
values={{ domain }}
/>
</a>
</nav>
</div>
</footer>
</main>
);
@@ -3,17 +3,13 @@ import type { FC } from 'react';
import { openModal } from '@/mastodon/actions/modal';
import { useDismissible } from '@/mastodon/hooks/useDismissible';
import {
generateReport,
selectWrapstodonYear,
} from '@/mastodon/reducers/slices/annual_report';
import { generateReport } from '@/mastodon/reducers/slices/annual_report';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import { AnnualReportAnnouncement } from './announcement';
export const AnnualReportTimeline: FC = () => {
const { state } = useAppSelector((state) => state.annualReport);
const year = useAppSelector(selectWrapstodonYear);
const { state, year } = useAppSelector((state) => state.annualReport);
const dispatch = useAppDispatch();
const handleBuildRequest = useCallback(() => {
@@ -4,6 +4,7 @@ import type { List } from 'immutable';
import { EmojiHTML } from '@/mastodon/components/emoji/html';
import { useElementHandledLink } from '@/mastodon/components/status/handled_link';
import type { CustomEmoji } from '@/mastodon/models/custom_emoji';
import type { Status } from '@/mastodon/models/status';
import type { Mention } from './embedded_status';
@@ -33,6 +34,7 @@ export const EmbeddedStatusContent: React.FC<{
className={className}
lang={status.get('language') as string}
htmlString={status.get('contentHtml') as string}
extraEmojis={status.get('emoji') as List<CustomEmoji>}
/>
);
};
@@ -21,6 +21,7 @@ import { PictureInPicture } from 'mastodon/features/picture_in_picture';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { layoutFromWindow } from 'mastodon/is_mobile';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
import { checkAnnualReport } from '@/mastodon/reducers/slices/annual_report';
import { uploadCompose, resetCompose, changeComposeSpoilerness } from '../../actions/compose';
import { clearHeight } from '../../actions/height_cache';
@@ -396,6 +397,7 @@ class UI extends PureComponent {
this.props.dispatch(expandHomeTimeline());
this.props.dispatch(fetchNotifications());
this.props.dispatch(fetchServerTranslationLanguages());
this.props.dispatch(checkAnnualReport());
setTimeout(() => this.props.dispatch(fetchServer()), 3000);
}