pl-fe: support mastodon link timeline
Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -16,6 +16,7 @@ import type {
|
||||
PaginatedResponse,
|
||||
PublicTimelineParams,
|
||||
Status as BaseStatus,
|
||||
LinkTimelineParams,
|
||||
} from 'pl-api';
|
||||
import type { AppDispatch, RootState } from 'pl-fe/store';
|
||||
|
||||
@ -293,6 +294,22 @@ const fetchHashtagTimeline = (hashtag: string, { tags }: Record<string, any> = {
|
||||
return dispatch(handleTimelineExpand(timelineId, fn, false, done));
|
||||
};
|
||||
|
||||
const fetchLinkTimeline = (url: string, expand = false, done = noOp) =>
|
||||
async (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const state = getState();
|
||||
const timelineId = `link:${url}`;
|
||||
|
||||
const params: LinkTimelineParams = {};
|
||||
|
||||
if (expand && state.timelines[timelineId]?.isLoading) return;
|
||||
|
||||
if (useSettingsStore.getState().settings.autoTranslate) params.language = getLocale();
|
||||
|
||||
const fn = (expand && state.timelines[timelineId]?.next?.()) || getClient(state).timelines.linkTimeline(url, params);
|
||||
|
||||
return dispatch(handleTimelineExpand(timelineId, fn, false, done));
|
||||
};
|
||||
|
||||
const expandTimelineRequest = (timeline: string) => ({
|
||||
type: TIMELINE_EXPAND_REQUEST,
|
||||
timeline,
|
||||
@ -361,6 +378,7 @@ export {
|
||||
fetchListTimeline,
|
||||
fetchGroupTimeline,
|
||||
fetchHashtagTimeline,
|
||||
fetchLinkTimeline,
|
||||
expandTimelineSuccess,
|
||||
scrollTopTimeline,
|
||||
type TimelineAction,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { TrendsLink } from 'pl-api';
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { getTextDirection } from 'pl-fe/utils/rtl';
|
||||
|
||||
@ -56,7 +57,11 @@ const TrendingLink: React.FC<ITrendingLink> = ({ trendingLink }) => {
|
||||
</Text>
|
||||
</HStack>
|
||||
|
||||
{!!count && accountsCountRenderer(count)}
|
||||
{!!count && (
|
||||
<Link to={`/links/${encodeURIComponent(trendingLink.url)}`} className='hover:underline'>
|
||||
{accountsCountRenderer(count)}
|
||||
</Link>
|
||||
)}
|
||||
</HStack>
|
||||
</Stack>
|
||||
</a>
|
||||
|
||||
56
packages/pl-fe/src/features/link-timeline/index.tsx
Normal file
56
packages/pl-fe/src/features/link-timeline/index.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { clearTimeline, fetchLinkTimeline } from 'pl-fe/actions/timelines';
|
||||
import Column from 'pl-fe/components/ui/column';
|
||||
import Timeline from 'pl-fe/features/ui/components/timeline';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useIsMobile } from 'pl-fe/hooks/use-is-mobile';
|
||||
import { useTheme } from 'pl-fe/hooks/use-theme';
|
||||
|
||||
const messages = defineMessages({
|
||||
header: { id: 'column.link_timeline', defaultMessage: 'Posts linking to {url}' },
|
||||
});
|
||||
|
||||
interface ILinkTimeline {
|
||||
params?: {
|
||||
url?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const HashtagTimeline: React.FC<ILinkTimeline> = ({ params }) => {
|
||||
const url = decodeURIComponent(params?.url || '');
|
||||
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
const theme = useTheme();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const handleLoadMore = () => {
|
||||
dispatch(fetchLinkTimeline(url, true));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(clearTimeline(`link:${url}`));
|
||||
dispatch(fetchLinkTimeline(url));
|
||||
}, [url]);
|
||||
|
||||
return (
|
||||
<Column
|
||||
label={intl.formatMessage(messages.header, { url: url.replace(/^https?:\/\//, '') })}
|
||||
transparent={!isMobile}
|
||||
>
|
||||
<Timeline
|
||||
className='black:p-0 black:sm:p-4 black:sm:pt-0'
|
||||
loadMoreClassName='black:sm:mx-4'
|
||||
scrollKey='link_timeline'
|
||||
timelineId={`link:${url}`}
|
||||
onLoadMore={handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.link_timeline' defaultMessage='There are no posts with this link yet.' />}
|
||||
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
export { HashtagTimeline as default };
|
||||
@ -108,6 +108,7 @@ import {
|
||||
InteractionPolicies,
|
||||
InteractionRequests,
|
||||
LandingTimeline,
|
||||
LinkTimeline,
|
||||
ListTimeline,
|
||||
Lists,
|
||||
LoginPage,
|
||||
@ -234,6 +235,7 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = React.memo(({ chil
|
||||
<Redirect from='/registration/:token' to='/invite/:token' />
|
||||
|
||||
<WrappedRoute path='/tags/:id' publicRoute layout={DefaultLayout} component={HashtagTimeline} content={children} />
|
||||
<WrappedRoute path='/links/:url' publicRoute layout={DefaultLayout} component={LinkTimeline} content={children} />
|
||||
|
||||
{features.lists && <WrappedRoute path='/lists' layout={DefaultLayout} component={Lists} content={children} />}
|
||||
{features.lists && <WrappedRoute path='/list/:id' layout={DefaultLayout} component={ListTimeline} content={children} />}
|
||||
|
||||
@ -59,6 +59,7 @@ export const IntentionalError = lazy(() => import('pl-fe/features/intentional-er
|
||||
export const InteractionPolicies = lazy(() => import('pl-fe/features/interaction-policies'));
|
||||
export const InteractionRequests = lazy(() => import('pl-fe/features/interaction-requests'));
|
||||
export const LandingTimeline = lazy(() => import('pl-fe/features/landing-timeline'));
|
||||
export const LinkTimeline = lazy(() => import('pl-fe/features/link-timeline'));
|
||||
export const Lists = lazy(() => import('pl-fe/features/lists'));
|
||||
export const ListTimeline = lazy(() => import('pl-fe/features/list-timeline'));
|
||||
export const LoginPage = lazy(() => import('pl-fe/features/auth-login/components/login-page'));
|
||||
|
||||
@ -402,6 +402,7 @@
|
||||
"column.info": "Server information",
|
||||
"column.interaction_policies": "Interaction policies",
|
||||
"column.interaction_requests": "Interaction requests",
|
||||
"column.link_timeline": "Posts linking to {url}",
|
||||
"column.lists": "Lists",
|
||||
"column.manage_group": "Manage group",
|
||||
"column.mentions": "Mentions",
|
||||
@ -741,6 +742,7 @@
|
||||
"empty_column.home.subtitle": "{siteTitle} gets more interesting once you follow other users.",
|
||||
"empty_column.home.title": "You're not following anyone yet",
|
||||
"empty_column.interaction_requests": "There are no pending interaction requests.",
|
||||
"empty_column.link_timeline": "There are no posts with this link yet.",
|
||||
"empty_column.list": "There is nothing in this list yet. When members of this list create new posts, they will appear here.",
|
||||
"empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.",
|
||||
"empty_column.mutes": "You haven't muted any users yet.",
|
||||
|
||||
Reference in New Issue
Block a user