diff --git a/src/app.css b/src/app.css
index c1cd1192..815169e5 100644
--- a/src/app.css
+++ b/src/app.css
@@ -1312,6 +1312,9 @@ body:has(.media-modal-container + .status-deck) .media-post-link {
.tag .icon {
vertical-align: middle;
}
+.tag.collapsed {
+ margin: 0;
+}
/* MENU POPUP */
diff --git a/src/components/follow-request-buttons.jsx b/src/components/follow-request-buttons.jsx
new file mode 100644
index 00000000..a40ba534
--- /dev/null
+++ b/src/components/follow-request-buttons.jsx
@@ -0,0 +1,54 @@
+import { useState } from 'preact/hooks';
+
+import { api } from '../utils/api';
+
+import Loader from './loader';
+
+function FollowRequestButtons({ accountID, onChange }) {
+ const { masto } = api();
+ const [uiState, setUIState] = useState('default');
+ return (
+
+ {' '}
+
+
+
+ );
+}
+
+export default FollowRequestButtons;
diff --git a/src/components/notification.jsx b/src/components/notification.jsx
index 0a1bf700..d3714119 100644
--- a/src/components/notification.jsx
+++ b/src/components/notification.jsx
@@ -2,6 +2,7 @@ import states from '../utils/states';
import store from '../utils/store';
import Avatar from './avatar';
+import FollowRequestButtons from './follow-request-buttons';
import Icon from './icon';
import Link from './link';
import NameText from './name-text';
@@ -205,51 +206,4 @@ function Notification({ notification, instance }) {
);
}
-function FollowRequestButtons({ accountID, onChange }) {
- const { masto } = api();
- const [uiState, setUIState] = useState('default');
- return (
-
- {' '}
-
-
-
- );
-}
-
export default Notification;
diff --git a/src/pages/home.jsx b/src/pages/home.jsx
index a30db85d..c1bc8d43 100644
--- a/src/pages/home.jsx
+++ b/src/pages/home.jsx
@@ -135,11 +135,20 @@ function NotificationsMenu({ anchorRef, state, onClose }) {
return allNotifications;
}
+ const [hasFollowRequests, setHasFollowRequests] = useState(false);
+ function fetchFollowRequests() {
+ return masto.v1.followRequests.list({
+ limit: 1,
+ });
+ }
+
function loadNotifications() {
setUIState('loading');
(async () => {
try {
await fetchNotifications();
+ const followRequests = await fetchFollowRequests();
+ setHasFollowRequests(!!followRequests?.length);
setUIState('default');
} catch (e) {
setUIState('error');
@@ -204,7 +213,15 @@ function NotificationsMenu({ anchorRef, state, onClose }) {
Mentions
- See all
+ {hasFollowRequests ? (
+ <>
+ New{' '}
+ Follow Requests
+ >
+ ) : (
+ See all
+ )}{' '}
+
diff --git a/src/pages/notifications.css b/src/pages/notifications.css
index 3e8f688b..3f399ccc 100644
--- a/src/pages/notifications.css
+++ b/src/pages/notifications.css
@@ -152,3 +152,41 @@
color: var(--text-color);
background-color: var(--bg-color);
}
+
+.follow-requests {
+ padding-block-end: 16px;
+}
+.follow-requests ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ max-height: 50vh;
+ max-height: 50dvh;
+ overflow: auto;
+ border-bottom: var(--hairline-width) solid var(--outline-color);
+}
+.follow-requests ul li {
+ display: flex;
+ align-items: center;
+ padding: 16px;
+ border-bottom: var(--hairline-width) solid var(--outline-color);
+ justify-content: space-between;
+ column-gap: 16px;
+ row-gap: 4px;
+ flex-wrap: wrap;
+}
+.follow-requests ul li:last-child {
+ border-bottom: none;
+}
+.follow-requests ul li .follow-request-buttons {
+ margin: 0;
+ padding: 0;
+ display: flex;
+ flex: 1;
+ gap: 4px;
+ justify-content: flex-end;
+ align-items: center;
+}
+.follow-requests ul li .follow-request-buttons .loader-container {
+ order: -1;
+}
diff --git a/src/pages/notifications.jsx b/src/pages/notifications.jsx
index 469b2f60..db525401 100644
--- a/src/pages/notifications.jsx
+++ b/src/pages/notifications.jsx
@@ -4,6 +4,8 @@ import { memo } from 'preact/compat';
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
import { useSnapshot } from 'valtio';
+import AccountBlock from '../components/account-block';
+import FollowRequestButtons from '../components/follow-request-buttons';
import Icon from '../components/icon';
import Link from '../components/link';
import Loader from '../components/loader';
@@ -31,6 +33,7 @@ function Notifications() {
scrollableRef,
});
const hiddenUI = scrollDirection === 'end' && !nearReachStart;
+ const [followRequests, setFollowRequests] = useState([]);
console.debug('RENDER Notifications');
@@ -67,12 +70,39 @@ function Notifications() {
return allNotifications;
}
+ async function fetchFollowRequests() {
+ const followRequests = await masto.v1.followRequests.list({
+ limit: 80,
+ });
+ // Note: no pagination here yet because this better be on a separate page. Should be rare use-case???
+ return followRequests;
+ }
+
+ const loadFollowRequests = () => {
+ setUIState('loading');
+ (async () => {
+ try {
+ const requests = await fetchFollowRequests();
+ setFollowRequests(requests);
+ setUIState('default');
+ } catch (e) {
+ setUIState('error');
+ }
+ })();
+ };
+
const loadNotifications = (firstLoad) => {
setUIState('loading');
(async () => {
try {
const { done } = await fetchNotifications(firstLoad);
setShowMore(!done);
+
+ if (firstLoad) {
+ const requests = await fetchFollowRequests();
+ setFollowRequests(requests);
+ }
+
setUIState('default');
} catch (e) {
setUIState('error');
@@ -184,6 +214,24 @@ function Notifications() {
)}
+ {followRequests.length > 0 && (
+
+
+
+ {followRequests.map((account) => (
+ -
+
+ {
+ loadFollowRequests();
+ }}
+ />
+
+ ))}
+
+
+ )}