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