1
0
Fork 0
mirror of https://github.com/cheeaun/phanpy.git synced 2025-03-31 19:11:35 +02:00
phanpy/src/pages/public.jsx

183 lines
5.3 KiB
React
Raw Normal View History

import { Trans, useLingui } from '@lingui/react/macro';
import { Menu, MenuDivider, MenuItem } from '@szhsin/react-menu';
import { useRef } from 'preact/hooks';
import { useNavigate, useParams } from 'react-router-dom';
import { useSnapshot } from 'valtio';
import Icon from '../components/icon';
2023-06-13 17:46:37 +08:00
import Menu2 from '../components/menu2';
import Timeline from '../components/timeline';
import { api } from '../utils/api';
2023-03-22 00:09:36 +08:00
import { filteredItems } from '../utils/filters';
import states, { saveStatus } from '../utils/states';
import supports from '../utils/supports';
2023-02-03 21:08:08 +08:00
import useTitle from '../utils/useTitle';
const LIMIT = 20;
function Public({ local, columnMode, ...props }) {
const { t } = useLingui();
const snapStates = useSnapshot(states);
2023-02-06 20:17:07 +08:00
const isLocal = !!local;
const params = columnMode ? {} : useParams();
2023-02-18 20:48:24 +08:00
const { masto, instance } = api({
instance: props?.instance || params.instance,
});
const { masto: currentMasto, instance: currentInstance } = api();
2024-08-13 15:26:23 +08:00
const title = isLocal
? t`Local timeline (${instance})`
: t`Federated timeline (${instance})`;
useTitle(title, isLocal ? `/:instance?/p/l` : `/:instance?/p`);
// const navigate = useNavigate();
2023-02-11 16:28:03 +08:00
const latestItem = useRef();
const publicIterator = useRef();
async function fetchPublic(firstLoad) {
if (firstLoad || !publicIterator.current) {
const opts = {
limit: LIMIT,
local: isLocal || undefined,
};
if (!isLocal && supports('@pixelfed/global-feed')) {
opts.remote = true;
}
publicIterator.current = masto.v1.timelines.public.list(opts);
}
2023-02-11 16:28:03 +08:00
const results = await publicIterator.current.next();
2023-03-22 00:09:36 +08:00
let { value } = results;
2023-02-11 16:28:03 +08:00
if (value?.length) {
if (firstLoad) {
latestItem.current = value[0].id;
}
// value = filteredItems(value, 'public');
value.forEach((item) => {
saveStatus(item, instance);
});
2023-02-11 16:28:03 +08:00
}
2023-05-14 21:13:36 +08:00
return {
...results,
value,
};
2023-02-11 16:28:03 +08:00
}
async function checkForUpdates() {
try {
const results = await masto.v1.timelines.public
.list({
2023-02-11 16:28:03 +08:00
limit: 1,
local: isLocal,
since_id: latestItem.current,
})
.next();
2023-03-22 00:09:36 +08:00
let { value } = results;
2024-04-09 23:35:17 +08:00
const valueContainsLatestItem = value[0]?.id === latestItem.current; // since_id might not be supported
if (value?.length && !valueContainsLatestItem) {
value = filteredItems(value, 'public');
2023-02-11 16:28:03 +08:00
return true;
}
return false;
} catch (e) {
return false;
}
}
return (
<Timeline
key={instance + isLocal}
2023-02-03 21:08:08 +08:00
title={title}
titleComponent={
<h1 class="header-double-lines">
2024-08-13 15:26:23 +08:00
<b>{isLocal ? t`Local timeline` : t`Federated timeline`}</b>
<div>{instance}</div>
</h1>
}
id="public"
instance={instance}
2024-08-13 15:26:23 +08:00
emptyText={t`No one has posted anything yet.`}
errorText={t`Unable to load posts`}
fetchItems={fetchPublic}
2023-02-11 16:28:03 +08:00
checkForUpdates={checkForUpdates}
useItemID
headerStart={<></>}
boostsCarousel={snapStates.settings.boostsCarousel}
// allowFilters
filterContext="public"
headerEnd={
2023-06-13 17:46:37 +08:00
<Menu2
portal
// setDownOverflow
overflow="auto"
viewScroll="close"
position="anchor"
menuButton={
<button type="button" class="plain">
2024-08-13 15:26:23 +08:00
<Icon icon="more" size="l" alt={t`More`} />
</button>
}
>
<MenuItem href={isLocal ? `/#/${instance}/p` : `/#/${instance}/p/l`}>
{isLocal ? (
<>
2024-08-13 15:26:23 +08:00
<Icon icon="transfer" />{' '}
<span>
<Trans>Switch to Federated</Trans>
</span>
</>
) : (
<>
2024-08-13 15:26:23 +08:00
<Icon icon="transfer" />{' '}
<span>
<Trans>Switch to Local</Trans>
</span>
</>
)}
</MenuItem>
<MenuDivider />
<MenuItem
onClick={() => {
let newInstance = prompt(
2024-08-13 15:26:23 +08:00
t`Enter a new instance e.g. "mastodon.social"`,
);
if (!/\./.test(newInstance)) {
2024-08-13 15:26:23 +08:00
if (newInstance) alert(t`Invalid instance`);
return;
}
if (newInstance) {
newInstance = newInstance.toLowerCase().trim();
// navigate(isLocal ? `/${newInstance}/p/l` : `/${newInstance}/p`);
location.hash = isLocal
? `/${newInstance}/p/l`
: `/${newInstance}/p`;
}
}}
>
2024-08-13 15:26:23 +08:00
<Icon icon="bus" />{' '}
<span>
<Trans>Go to another instance</Trans>
</span>
</MenuItem>
{currentInstance !== instance && (
<MenuItem
onClick={() => {
location.hash = isLocal
? `/${currentInstance}/p/l`
: `/${currentInstance}/p`;
}}
>
<Icon icon="bus" />{' '}
<small class="menu-double-lines">
2024-08-13 15:26:23 +08:00
<Trans>
Go to my instance (<b>{currentInstance}</b>)
</Trans>
</small>
</MenuItem>
)}
2023-06-13 17:46:37 +08:00
</Menu2>
}
/>
);
}
export default Public;