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 ? ( + <> + {' '} + 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 && ( + + )}