Merge remote-tracking branch 'parent/main' into upstream-20240705
This commit is contained in:
commit
9a07550fa6
75 changed files with 1046 additions and 543 deletions
|
@ -98,7 +98,7 @@ const messageForFollowButton = relationship => {
|
|||
return messages.mutual;
|
||||
} else if (!relationship.get('following') && relationship.get('followed_by') && isShowItem('relationships')) {
|
||||
return messages.followBack;
|
||||
} else if (relationship.get('following')) {
|
||||
} else if (relationship.get('following') || relationship.get('requested')) {
|
||||
return messages.unfollow;
|
||||
} else {
|
||||
return messages.follow;
|
||||
|
@ -313,10 +313,8 @@ class Header extends ImmutablePureComponent {
|
|||
if (me !== account.get('id')) {
|
||||
if (signedIn && !account.get('relationship')) { // Wait until the relationship is loaded
|
||||
actionBtn = <Button disabled><LoadingIndicator /></Button>;
|
||||
} else if (account.getIn(['relationship', 'requested'])) {
|
||||
actionBtn = <Button text={intl.formatMessage(messages.cancel_follow_request)} title={intl.formatMessage(messages.requested)} onClick={this.props.onFollow} />;
|
||||
} else if (!account.getIn(['relationship', 'blocking'])) {
|
||||
actionBtn = <Button disabled={account.getIn(['relationship', 'blocked_by'])} className={classNames({ 'button--destructive': account.getIn(['relationship', 'following']) })} text={intl.formatMessage(messageForFollowButton(account.get('relationship')))} onClick={signedIn ? this.props.onFollow : this.props.onInteractionModal} />;
|
||||
actionBtn = <Button disabled={account.getIn(['relationship', 'blocked_by'])} className={classNames({ 'button--destructive': (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) })} text={intl.formatMessage(messageForFollowButton(account.get('relationship')))} onClick={signedIn ? this.props.onFollow : this.props.onInteractionModal} />;
|
||||
} else if (account.getIn(['relationship', 'blocking'])) {
|
||||
actionBtn = <Button text={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.props.onBlock} />;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ import { makeGetAccount, getAccountHidden } from '../../../selectors';
|
|||
import Header from '../components/header';
|
||||
|
||||
const messages = defineMessages({
|
||||
cancelFollowRequestConfirm: { id: 'confirmations.cancel_follow_request.confirm', defaultMessage: 'Withdraw request' },
|
||||
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Block entire domain' },
|
||||
});
|
||||
|
@ -46,7 +45,7 @@ const makeMapStateToProps = () => {
|
|||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
|
||||
onFollow (account) {
|
||||
if (account.getIn(['relationship', 'following'])) {
|
||||
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
|
||||
dispatch(openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalProps: {
|
||||
|
@ -55,15 +54,6 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
|
||||
},
|
||||
}));
|
||||
} else if (account.getIn(['relationship', 'requested'])) {
|
||||
dispatch(openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalProps: {
|
||||
message: <FormattedMessage id='confirmations.cancel_follow_request.message' defaultMessage='Are you sure you want to withdraw your request to follow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.cancelFollowRequestConfirm),
|
||||
onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
|
||||
},
|
||||
}));
|
||||
} else {
|
||||
dispatch(followAccount(account.get('id')));
|
||||
}
|
||||
|
|
|
@ -163,7 +163,7 @@ export const Conversation = ({ conversation, scrollKey, onMoveUp, onMoveDown })
|
|||
menu.push({ text: intl.formatMessage(messages.delete), action: handleDelete });
|
||||
|
||||
const names = accounts.map(a => (
|
||||
<Link to={`/@${a.get('acct')}`} key={a.get('id')} title={a.get('acct')}>
|
||||
<Link to={`/@${a.get('acct')}`} key={a.get('id')} data-hover-card-account={a.get('id')}>
|
||||
<bdi>
|
||||
<strong
|
||||
className='display-name__html'
|
||||
|
|
|
@ -4,6 +4,8 @@ import { useState, useCallback } from 'react';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
|
||||
|
||||
import { Blurhash } from 'mastodon/components/blurhash';
|
||||
|
@ -57,7 +59,7 @@ export const Story = ({
|
|||
|
||||
<div className='story__details__shared'>
|
||||
{author ? <FormattedMessage id='link_preview.author' className='story__details__shared__author' defaultMessage='By {name}' values={{ name: authorAccount ? <AuthorLink accountId={authorAccount} /> : <strong>{author}</strong> }} /> : <span />}
|
||||
{typeof sharedTimes === 'number' ? <span className='story__details__shared__pill'><ShortNumber value={sharedTimes} renderer={sharesCountRenderer} /></span> : <Skeleton width='10ch' />}
|
||||
{typeof sharedTimes === 'number' ? <Link className='story__details__shared__pill' to={`/links/${encodeURIComponent(url)}`}><ShortNumber value={sharedTimes} renderer={sharesCountRenderer} /></Link> : <Skeleton width='10ch' />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
76
app/javascript/mastodon/features/link_timeline/index.tsx
Normal file
76
app/javascript/mastodon/features/link_timeline/index.tsx
Normal file
|
@ -0,0 +1,76 @@
|
|||
import { useRef, useEffect, useCallback } from 'react';
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import ExploreIcon from '@/material-icons/400-24px/explore.svg?react';
|
||||
import { expandLinkTimeline } from 'mastodon/actions/timelines';
|
||||
import Column from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import StatusListContainer from 'mastodon/features/ui/containers/status_list_container';
|
||||
import type { Card } from 'mastodon/models/status';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
export const LinkTimeline: React.FC<{
|
||||
multiColumn: boolean;
|
||||
}> = ({ multiColumn }) => {
|
||||
const { url } = useParams<{ url: string }>();
|
||||
const decodedUrl = url ? decodeURIComponent(url) : undefined;
|
||||
const dispatch = useAppDispatch();
|
||||
const columnRef = useRef<Column>(null);
|
||||
const firstStatusId = useAppSelector((state) =>
|
||||
decodedUrl
|
||||
? // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
||||
(state.timelines.getIn([`link:${decodedUrl}`, 'items', 0]) as string)
|
||||
: undefined,
|
||||
);
|
||||
const story = useAppSelector((state) =>
|
||||
firstStatusId
|
||||
? (state.statuses.getIn([firstStatusId, 'card']) as Card)
|
||||
: undefined,
|
||||
);
|
||||
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current?.scrollTop();
|
||||
}, []);
|
||||
|
||||
const handleLoadMore = useCallback(
|
||||
(maxId: string) => {
|
||||
dispatch(expandLinkTimeline(decodedUrl, { maxId }));
|
||||
},
|
||||
[dispatch, decodedUrl],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(expandLinkTimeline(decodedUrl));
|
||||
}, [dispatch, decodedUrl]);
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={columnRef} label={story?.title}>
|
||||
<ColumnHeader
|
||||
icon='explore'
|
||||
iconComponent={ExploreIcon}
|
||||
title={story?.title}
|
||||
onClick={handleHeaderClick}
|
||||
multiColumn={multiColumn}
|
||||
showBackButton
|
||||
/>
|
||||
|
||||
<StatusListContainer
|
||||
timelineId={`link:${decodedUrl}`}
|
||||
onLoadMore={handleLoadMore}
|
||||
trackScroll
|
||||
scrollKey={`link_timeline-${decodedUrl}`}
|
||||
bindToDocument={!multiColumn}
|
||||
/>
|
||||
|
||||
<Helmet>
|
||||
<title>{story?.title}</title>
|
||||
<meta name='robots' content='noindex' />
|
||||
</Helmet>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default LinkTimeline;
|
|
@ -63,6 +63,7 @@ import {
|
|||
BookmarkCategories,
|
||||
BookmarkCategoryStatuses,
|
||||
FollowedTags,
|
||||
LinkTimeline,
|
||||
ListTimeline,
|
||||
Blocks,
|
||||
DomainBlocks,
|
||||
|
@ -217,6 +218,7 @@ class SwitchingColumnsArea extends PureComponent {
|
|||
<WrappedRoute path='/public/local/fixed' exact component={CommunityTimeline} content={children} />
|
||||
<WrappedRoute path={['/conversations', '/timelines/direct']} component={DirectTimeline} content={children} />
|
||||
<WrappedRoute path='/tags/:id' component={HashtagTimeline} content={children} />
|
||||
<WrappedRoute path='/links/:url' component={LinkTimeline} content={children} />
|
||||
<WrappedRoute path='/lists/:id' component={ListTimeline} content={children} />
|
||||
<WrappedRoute path='/antennasw/:id' component={AntennaSetting} content={children} />
|
||||
<WrappedRoute path='/antennast/:id' component={AntennaTimeline} content={children} />
|
||||
|
|
|
@ -269,3 +269,7 @@ export function NotificationRequests () {
|
|||
export function NotificationRequest () {
|
||||
return import(/*webpackChunkName: "features/notifications/request" */'../../notifications/request');
|
||||
}
|
||||
|
||||
export function LinkTimeline () {
|
||||
return import(/*webpackChunkName: "features/link_timeline" */'../../link_timeline');
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue