diff --git a/src/app.jsx b/src/app.jsx
index 8e4001aa..391e2e45 100644
--- a/src/app.jsx
+++ b/src/app.jsx
@@ -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() {
} />
} />
+ } />
} />
{/* } /> */}
diff --git a/src/components/icon.jsx b/src/components/icon.jsx
index afc6e906..0d37deb6 100644
--- a/src/components/icon.jsx
+++ b/src/components/icon.jsx
@@ -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');
diff --git a/src/components/menu.jsx b/src/components/menu.jsx
index 7e36ca83..363e5219 100644
--- a/src/components/menu.jsx
+++ b/src/components/menu.jsx
@@ -137,6 +137,9 @@ function NavMenu(props) {
Federated
+
+ Trending
+
{authenticated && (
<>
diff --git a/src/pages/trending.jsx b/src/pages/trending.jsx
new file mode 100644
index 00000000..c92a7e11
--- /dev/null
+++ b/src/pages/trending.jsx
@@ -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 (
+