Add Trending page

This commit is contained in:
Lim Chee Aun 2023-04-06 01:14:38 +08:00
parent f1bb1454c3
commit 913a352dee
4 changed files with 133 additions and 0 deletions

View file

@ -41,6 +41,7 @@ import Public from './pages/public';
import Search from './pages/search';
import Settings from './pages/settings';
import Status from './pages/status';
import Trending from './pages/trending';
import Welcome from './pages/welcome';
import {
api,
@ -238,6 +239,7 @@ function App() {
<Route index element={<Public />} />
<Route path="l" element={<Public local />} />
</Route>
<Route path="/:instance?/trending" element={<Trending />} />
<Route path="/:instance?/search" element={<Search />} />
{/* <Route path="/:anything" element={<NotFound />} /> */}
</Routes>

View file

@ -75,6 +75,7 @@ const ICONS = {
refresh: 'mingcute:refresh-2-line',
emoji2: 'mingcute:emoji-2-line',
filter: 'mingcute:filter-2-line',
chart: 'mingcute:chart-line-line',
};
const modules = import.meta.glob('/node_modules/@iconify-icons/mingcute/*.js');

View file

@ -137,6 +137,9 @@ function NavMenu(props) {
<MenuLink to={`/${instance}/p`}>
<Icon icon="earth" size="l" /> <span>Federated</span>
</MenuLink>
<MenuLink to={`/${instance}/trending`}>
<Icon icon="chart" size="l" /> <span>Trending</span>
</MenuLink>
{authenticated && (
<>
<MenuDivider />

127
src/pages/trending.jsx Normal file
View file

@ -0,0 +1,127 @@
import { Menu, 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';
import Timeline from '../components/timeline';
import { api } from '../utils/api';
import { filteredItems } from '../utils/filters';
import states from '../utils/states';
import { saveStatus } from '../utils/states';
import useTitle from '../utils/useTitle';
const LIMIT = 20;
function Trending(props) {
const snapStates = useSnapshot(states);
const params = useParams();
const { masto, instance } = api({
instance: props?.instance || params.instance,
});
const title = `Trending (${instance})`;
useTitle(title, `/:instance?/trending`);
const navigate = useNavigate();
const latestItem = useRef();
const trendIterator = useRef();
async function fetchTrend(firstLoad) {
if (firstLoad || !trendIterator.current) {
trendIterator.current = masto.v1.trends.listStatuses({
limit: LIMIT,
});
}
const results = await trendIterator.current.next();
let { value } = results;
if (value?.length) {
if (firstLoad) {
latestItem.current = value[0].id;
}
value = filteredItems(value, 'public'); // Might not work here
value.forEach((item) => {
saveStatus(item, instance);
});
}
return results;
}
async function checkForUpdates() {
try {
const results = await masto.v1.trends
.listStatuses({
limit: 1,
since_id: latestItem.current,
})
.next();
let { value } = results;
value = filteredItems(value, 'public');
if (value?.length) {
return true;
}
return false;
} catch (e) {
return false;
}
}
return (
<Timeline
key={instance}
title={title}
titleComponent={
<h1 class="header-account">
<b>Trending</b>
<div>{instance}</div>
</h1>
}
id="trending"
instance={instance}
emptyText="No trending posts."
errorText="Unable to load posts"
fetchItems={fetchTrend}
checkForUpdates={checkForUpdates}
useItemID
headerStart={<></>}
boostsCarousel={snapStates.settings.boostsCarousel}
allowFilters
headerEnd={
<Menu
portal={{
target: document.body,
}}
// setDownOverflow
overflow="auto"
viewScroll="close"
position="anchor"
boundingBoxPadding="8 8 8 8"
menuButton={
<button type="button" class="plain">
<Icon icon="more" size="l" />
</button>
}
>
<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(`/${newInstance}/trending`);
}
}}
>
<Icon icon="bus" /> <span>Go to another instance</span>
</MenuItem>
</Menu>
}
/>
);
}
export default Trending;