Merge commit 'b57687083f4af178f2e2f43665eb4e49d32a50c2' into glitch-soc/merge-upstream

This commit is contained in:
Claire
2025-03-07 17:37:36 +01:00
94 changed files with 280 additions and 146 deletions

View File

@@ -1,7 +1,7 @@
import './public-path';
import { createRoot } from 'react-dom/client';
import { afterInitialRender } from 'mastodon/../hooks/useRenderSignal';
import { afterInitialRender } from 'mastodon/hooks/useRenderSignal';
import { start } from '../mastodon/common';
import { Status } from '../mastodon/features/standalone/status';

View File

@@ -29,7 +29,7 @@ const debouncedSave = debounce((dispatch, getState) => {
api().put('/api/web/settings', { data })
.then(() => dispatch({ type: SETTING_SAVE }))
.catch(error => dispatch(showAlertForError(error)));
}, 5000, { trailing: true });
}, 2000, { leading: true, trailing: true });
export function saveSettings() {
return (dispatch, getState) => debouncedSave(dispatch, getState);

View File

@@ -4,8 +4,12 @@ import type {
ApiPrivacyPolicyJSON,
} from 'mastodon/api_types/instance';
export const apiGetTermsOfService = () =>
apiRequestGet<ApiTermsOfServiceJSON>('v1/instance/terms_of_service');
export const apiGetTermsOfService = (version?: string) =>
apiRequestGet<ApiTermsOfServiceJSON>(
version
? `v1/instance/terms_of_service/${version}`
: 'v1/instance/terms_of_service',
);
export const apiGetPrivacyPolicy = () =>
apiRequestGet<ApiPrivacyPolicyJSON>('v1/instance/privacy_policy');

View File

@@ -1,5 +1,7 @@
export interface ApiTermsOfServiceJSON {
updated_at: string;
effective_date: string;
effective: boolean;
succeeded_by: string | null;
content: string;
}

View File

@@ -1,4 +1,4 @@
import { useLinks } from 'mastodon/../hooks/useLinks';
import { useLinks } from 'mastodon/hooks/useLinks';
export const AccountBio: React.FC<{
note: string;

View File

@@ -1,8 +1,8 @@
import classNames from 'classnames';
import CheckIcon from '@/material-icons/400-24px/check.svg?react';
import { useLinks } from 'mastodon/../hooks/useLinks';
import { Icon } from 'mastodon/components/icon';
import { useLinks } from 'mastodon/hooks/useLinks';
import type { Account } from 'mastodon/models/account';
export const AccountFields: React.FC<{

View File

@@ -8,7 +8,7 @@ import type {
UsePopperOptions,
} from 'react-overlays/esm/usePopper';
import { useSelectableClick } from '@/hooks/useSelectableClick';
import { useSelectableClick } from 'mastodon/hooks/useSelectableClick';
const offset = [0, 4] as OffsetValue;
const popperConfig = { strategy: 'fixed' } as UsePopperOptions;

View File

@@ -2,7 +2,7 @@ import { useState, useCallback } from 'react';
import classNames from 'classnames';
import { useHovering } from 'mastodon/../hooks/useHovering';
import { useHovering } from 'mastodon/hooks/useHovering';
import { autoPlayGif } from 'mastodon/initial_state';
import type { Account } from 'mastodon/models/account';

View File

@@ -1,8 +1,7 @@
import { useHovering } from 'mastodon/hooks/useHovering';
import { autoPlayGif } from 'mastodon/initial_state';
import type { Account } from 'mastodon/models/account';
import { useHovering } from '../../hooks/useHovering';
import { autoPlayGif } from '../initial_state';
interface Props {
account: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
friend: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there

View File

@@ -5,8 +5,8 @@ import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react';
import { useTimeout } from 'mastodon/../hooks/useTimeout';
import { Icon } from 'mastodon/components/icon';
import { useTimeout } from 'mastodon/hooks/useTimeout';
export const CopyPasteText: React.FC<{ value: string }> = ({ value }) => {
const inputRef = useRef<HTMLTextAreaElement>(null);

View File

@@ -1,4 +1,4 @@
import { useHovering } from '@/hooks/useHovering';
import { useHovering } from 'mastodon/hooks/useHovering';
import { autoPlayGif } from 'mastodon/initial_state';
export const GIF: React.FC<{

View File

@@ -8,8 +8,8 @@ import type {
UsePopperOptions,
} from 'react-overlays/esm/usePopper';
import { useTimeout } from 'mastodon/../hooks/useTimeout';
import { HoverCardAccount } from 'mastodon/components/hover_card_account';
import { useTimeout } from 'mastodon/hooks/useTimeout';
const offset = [-12, 4] as OffsetValue;
const enterDelay = 750;

View File

@@ -6,7 +6,6 @@ import classNames from 'classnames';
import { Helmet } from 'react-helmet';
import { NavLink } from 'react-router-dom';
import { useLinks } from '@/hooks/useLinks';
import CheckIcon from '@/material-icons/400-24px/check.svg?react';
import LockIcon from '@/material-icons/400-24px/lock.svg?react';
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
@@ -46,6 +45,7 @@ import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
import { DomainPill } from 'mastodon/features/account/components/domain_pill';
import AccountNoteContainer from 'mastodon/features/account/containers/account_note_container';
import FollowRequestNoteContainer from 'mastodon/features/account/containers/follow_request_note_container';
import { useLinks } from 'mastodon/hooks/useLinks';
import { useIdentity } from 'mastodon/identity_context';
import { autoPlayGif, me, domain as localDomain } from 'mastodon/initial_state';
import type { Account } from 'mastodon/models/account';

View File

@@ -6,9 +6,9 @@ import classNames from 'classnames';
import Overlay from 'react-overlays/Overlay';
import { useSelectableClick } from '@/hooks/useSelectableClick';
import QuestionMarkIcon from '@/material-icons/400-24px/question_mark.svg?react';
import { Icon } from 'mastodon/components/icon';
import { useSelectableClick } from 'mastodon/hooks/useSelectableClick';
const messages = defineMessages({
help: { id: 'info_button.label', defaultMessage: 'Help' },

View File

@@ -22,10 +22,9 @@ import { LoadMore } from 'mastodon/components/load_more';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import { RadioButton } from 'mastodon/components/radio_button';
import ScrollContainer from 'mastodon/containers/scroll_container';
import { useSearchParam } from 'mastodon/hooks/useSearchParam';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
import { useSearchParam } from '../../../hooks/useSearchParam';
import { AccountCard } from './components/account_card';
const messages = defineMessages({

View File

@@ -4,7 +4,6 @@ import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
import { Helmet } from 'react-helmet';
import { useSearchParam } from '@/hooks/useSearchParam';
import FindInPageIcon from '@/material-icons/400-24px/find_in_page.svg?react';
import PeopleIcon from '@/material-icons/400-24px/group.svg?react';
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
@@ -20,6 +19,7 @@ import { Icon } from 'mastodon/components/icon';
import ScrollableList from 'mastodon/components/scrollable_list';
import Status from 'mastodon/containers/status_container';
import { Search } from 'mastodon/features/compose/components/search';
import { useSearchParam } from 'mastodon/hooks/useSearchParam';
import type { Hashtag as HashtagType } from 'mastodon/models/tags';
import { useAppDispatch, useAppSelector } from 'mastodon/store';

View File

@@ -6,11 +6,11 @@ import { useEffect, useCallback } from 'react';
import { Provider } from 'react-redux';
import { useRenderSignal } from 'mastodon/../hooks/useRenderSignal';
import { fetchStatus, toggleStatusSpoilers } from 'mastodon/actions/statuses';
import { hydrateStore } from 'mastodon/actions/store';
import { Router } from 'mastodon/components/router';
import { DetailedStatus } from 'mastodon/features/status/components/detailed_status';
import { useRenderSignal } from 'mastodon/hooks/useRenderSignal';
import initialState from 'mastodon/initial_state';
import { IntlProvider } from 'mastodon/locales';
import { makeGetStatus, makeGetPictureInPicture } from 'mastodon/selectors';

View File

@@ -221,12 +221,12 @@ export const DetailedStatus: React.FC<{
/>
);
}
} else if (status.get('spoiler_text').length === 0) {
} else if (status.get('card')) {
media = (
<Card
sensitive={status.get('sensitive')}
onOpenMedia={onOpenMedia}
card={status.get('card', null)}
card={status.get('card')}
/>
);
}

View File

@@ -8,26 +8,31 @@ import {
} from 'react-intl';
import { Helmet } from 'react-helmet';
import { Link, useParams } from 'react-router-dom';
import { apiGetTermsOfService } from 'mastodon/api/instance';
import type { ApiTermsOfServiceJSON } from 'mastodon/api_types/instance';
import { Column } from 'mastodon/components/column';
import { Skeleton } from 'mastodon/components/skeleton';
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
const messages = defineMessages({
title: { id: 'terms_of_service.title', defaultMessage: 'Terms of Service' },
});
interface Params {
date?: string;
}
const TermsOfService: React.FC<{
multiColumn: boolean;
}> = ({ multiColumn }) => {
const intl = useIntl();
const { date } = useParams<Params>();
const [response, setResponse] = useState<ApiTermsOfServiceJSON>();
const [loading, setLoading] = useState(true);
useEffect(() => {
apiGetTermsOfService()
apiGetTermsOfService(date)
.then((data) => {
setResponse(data);
setLoading(false);
@@ -36,7 +41,7 @@ const TermsOfService: React.FC<{
.catch(() => {
setLoading(false);
});
}, []);
}, [date]);
if (!loading && !response) {
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
@@ -55,23 +60,60 @@ const TermsOfService: React.FC<{
defaultMessage='Terms of Service'
/>
</h3>
<p>
<FormattedMessage
id='privacy_policy.last_updated'
defaultMessage='Last updated {date}'
values={{
date: loading ? (
<Skeleton width='10ch' />
) : (
<FormattedDate
value={response?.updated_at}
year='numeric'
month='short'
day='2-digit'
<p className='prose'>
{response?.effective ? (
<FormattedMessage
id='privacy_policy.last_updated'
defaultMessage='Last updated {date}'
values={{
date: (
<FormattedDate
value={response.effective_date}
year='numeric'
month='short'
day='2-digit'
/>
),
}}
/>
) : (
<FormattedMessage
id='terms_of_service.effective_as_of'
defaultMessage='Effective as of {date}'
values={{
date: (
<FormattedDate
value={response?.effective_date}
year='numeric'
month='short'
day='2-digit'
/>
),
}}
/>
)}
{response?.succeeded_by && (
<>
{' · '}
<Link to={`/terms-of-service/${response.succeeded_by}`}>
<FormattedMessage
id='terms_of_service.upcoming_changes_on'
defaultMessage='Upcoming changes on {date}'
values={{
date: (
<FormattedDate
value={response.succeeded_by}
year='numeric'
month='short'
day='2-digit'
/>
),
}}
/>
),
}}
/>
</Link>
</>
)}
</p>
</div>

View File

@@ -205,7 +205,7 @@ class SwitchingColumnsArea extends PureComponent {
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
<WrappedRoute path='/about' component={About} content={children} />
<WrappedRoute path='/privacy-policy' component={PrivacyPolicy} content={children} />
<WrappedRoute path='/terms-of-service' component={TermsOfService} content={children} />
<WrappedRoute path='/terms-of-service/:date?' component={TermsOfService} content={children} />
<WrappedRoute path={['/home', '/timelines/home']} component={HomeTimeline} content={children} />
<Redirect from='/timelines/public' to='/public' exact />

View File

@@ -872,7 +872,9 @@
"subscribed_languages.target": "Change subscribed languages for {target}",
"tabs_bar.home": "Home",
"tabs_bar.notifications": "Notifications",
"terms_of_service.effective_as_of": "Effective as of {date}",
"terms_of_service.title": "Terms of Service",
"terms_of_service.upcoming_changes_on": "Upcoming changes on {date}",
"time_remaining.days": "{number, plural, one {# day} other {# days}} left",
"time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
"time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",

View File

@@ -2005,6 +2005,11 @@ a.sparkline {
line-height: 20px;
font-weight: 600;
margin-bottom: 16px;
a {
color: inherit;
text-decoration: none;
}
}
}
}

View File

@@ -340,10 +340,17 @@ code {
columns: unset;
}
.input.datetime .label_input select {
display: inline-block;
width: auto;
flex: 0;
.input.datetime .label_input,
.input.date .label_input {
display: flex;
gap: 4px;
align-items: center;
select {
display: inline-block;
width: auto;
flex: 0;
}
}
.input.select.select--languages {