Merge branch 'fork' into pl-api
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
commit
6f2b12c7ca
5 changed files with 62 additions and 48 deletions
|
@ -50,6 +50,7 @@ const DropdownMenu = (props: IDropdownMenu) => {
|
|||
const history = useHistory();
|
||||
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
const [isDisplayed, setIsDisplayed] = useState<boolean>(false);
|
||||
|
||||
const arrowRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
|
@ -254,6 +255,10 @@ const DropdownMenu = (props: IDropdownMenu) => {
|
|||
}
|
||||
}, [isOpen, refs.floating.current]);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => setIsDisplayed(isOpen), isOpen ? 0 : 150);
|
||||
}, [isOpen]);
|
||||
|
||||
if (items.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -284,14 +289,23 @@ const DropdownMenu = (props: IDropdownMenu) => {
|
|||
/>
|
||||
)}
|
||||
|
||||
{isOpen ? (
|
||||
{isOpen || isDisplayed ? (
|
||||
<Portal>
|
||||
<div
|
||||
data-testid='dropdown-menu'
|
||||
ref={refs.setFloating}
|
||||
className={
|
||||
clsx('z-[1001] w-56 rounded-md bg-white py-1 shadow-lg transition-opacity duration-100 focus:outline-none black:bg-black dark:bg-gray-900 dark:ring-2 dark:ring-primary-700', {
|
||||
'opacity-0 pointer-events-none': !isOpen,
|
||||
clsx('z-[1001] w-56 rounded-md bg-white py-1 shadow-lg duration-100 ease-in-out focus:outline-none black:bg-black no-reduce-motion:transition-transform dark:bg-gray-900 dark:ring-2 dark:ring-primary-700', {
|
||||
'scale-0': !(isDisplayed && isOpen),
|
||||
'scale-100': (isDisplayed && isOpen),
|
||||
'origin-bottom': placement === 'top',
|
||||
'origin-left': placement === 'right',
|
||||
'origin-top': placement === 'bottom',
|
||||
'origin-right': placement === 'left',
|
||||
'origin-bottom-left': placement === 'top-start',
|
||||
'origin-bottom-right': placement === 'top-end',
|
||||
'origin-top-left': placement === 'bottom-start',
|
||||
'origin-top-right': placement === 'bottom-end',
|
||||
})
|
||||
}
|
||||
style={{
|
||||
|
|
|
@ -9,7 +9,7 @@ import { getSettings } from 'soapbox/actions/settings';
|
|||
import { closeSidebar } from 'soapbox/actions/sidebar';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import Account from 'soapbox/components/account';
|
||||
import { Stack, Divider, HStack, Icon, IconButton, Text } from 'soapbox/components/ui';
|
||||
import { Stack, Divider, HStack, Icon, Text } from 'soapbox/components/ui';
|
||||
import ProfileStats from 'soapbox/features/ui/components/profile-stats';
|
||||
import { useAppDispatch, useAppSelector, useFeatures, useInstance } from 'soapbox/hooks';
|
||||
import { makeGetOtherAccounts } from 'soapbox/selectors';
|
||||
|
@ -28,6 +28,7 @@ const messages = defineMessages({
|
|||
groups: { id: 'column.groups', defaultMessage: 'Groups' },
|
||||
events: { id: 'column.events', defaultMessage: 'Events' },
|
||||
developers: { id: 'navigation.developers', defaultMessage: 'Developers' },
|
||||
dashboard: { id: 'navigation.dashboard', defaultMessage: 'Dashboard' },
|
||||
drafts: { id: 'navigation.drafts', defaultMessage: 'Drafts' },
|
||||
addAccount: { id: 'profile_dropdown.add_account', defaultMessage: 'Add an existing account' },
|
||||
followRequests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
||||
|
@ -83,6 +84,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
const settings = useAppSelector((state) => getSettings(state));
|
||||
const followRequestsCount = useAppSelector((state) => state.user_lists.follow_requests.items.count());
|
||||
const draftCount = useAppSelector((state) => state.draft_statuses.size);
|
||||
// const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());
|
||||
const [sidebarVisible, setSidebarVisible] = useState(sidebarOpen);
|
||||
const [touchStart, setTouchStart] = useState(0);
|
||||
const [touchEnd, setTouchEnd] = useState(0);
|
||||
|
@ -91,7 +93,6 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
const restrictUnauth = instance.pleroma.metadata.restrict_unauthenticated;
|
||||
|
||||
const containerRef = React.useRef<HTMLDivElement>(null);
|
||||
const closeButtonRef = React.useRef(null);
|
||||
|
||||
const [switcher, setSwitcher] = React.useState(false);
|
||||
|
||||
|
@ -148,6 +149,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (sidebarOpen) containerRef.current?.querySelector('a')?.focus();
|
||||
setTimeout(() => setSidebarVisible(sidebarOpen), sidebarOpen ? 0 : 150);
|
||||
}, [sidebarOpen]);
|
||||
|
||||
|
@ -169,7 +171,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
<div
|
||||
className={clsx('fixed inset-0 bg-gray-500 black:bg-gray-900 no-reduce-motion:transition-opacity dark:bg-gray-700', {
|
||||
'opacity-0': !(sidebarVisible && sidebarOpen),
|
||||
'opacity-90': (sidebarVisible && sidebarOpen),
|
||||
'opacity-40': (sidebarVisible && sidebarOpen),
|
||||
})}
|
||||
role='button'
|
||||
onClick={handleClose}
|
||||
|
@ -181,21 +183,12 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
>
|
||||
<div
|
||||
className={
|
||||
clsx({
|
||||
'flex flex-col flex-1 bg-white black:bg-black dark:bg-primary-900 -translate-x-full rtl:translate-x-full w-full max-w-xs no-reduce-motion:transition-transform ease-in-out': true,
|
||||
'!translate-x-0': sidebarVisible && sidebarOpen,
|
||||
clsx('rtl:r-2 fixed bottom-[60px] left-2 flex max-h-[calc(100dvh-68px)] w-full max-w-xs flex-1 origin-bottom-left flex-col rounded-xl bg-white shadow-lg ease-in-out black:bg-black no-reduce-motion:transition-transform rtl:right-2 rtl:origin-bottom-right dark:border dark:border-gray-800 dark:bg-primary-900 dark:shadow-none', {
|
||||
'scale-100': sidebarVisible && sidebarOpen,
|
||||
'scale-0': !(sidebarVisible && sidebarOpen),
|
||||
})
|
||||
}
|
||||
>
|
||||
<IconButton
|
||||
title={intl.formatMessage(messages.close)}
|
||||
onClick={handleClose}
|
||||
src={require('@tabler/icons/outline/x.svg')}
|
||||
ref={closeButtonRef}
|
||||
iconClassName='h-6 w-6'
|
||||
className='absolute right-0 top-0 -mr-11 mt-2 text-gray-600 hover:text-gray-600 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
/>
|
||||
|
||||
<div className='relative h-full w-full overflow-auto overflow-y-scroll'>
|
||||
<div className='p-4'>
|
||||
{account ? (
|
||||
|
@ -338,6 +331,16 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
/>
|
||||
)}
|
||||
|
||||
{account.staff && (
|
||||
<SidebarLink
|
||||
to='/dashboard'
|
||||
icon={require('@tabler/icons/outline/dashboard.svg')}
|
||||
text={intl.formatMessage(messages.dashboard)}
|
||||
onClick={onClose}
|
||||
// count={dashboardCount} WIP
|
||||
/>
|
||||
)}
|
||||
|
||||
<Divider />
|
||||
|
||||
<SidebarLink
|
||||
|
@ -427,13 +430,6 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Dummy element to keep Close Icon visible */}
|
||||
<div
|
||||
aria-hidden
|
||||
className='w-14 shrink-0'
|
||||
onClick={handleClose}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -89,7 +89,7 @@ const StatusActionButton = React.forwardRef<HTMLButtonElement, IStatusActionButt
|
|||
'-m-1 flex items-center rounded-full p-2 rtl:space-x-reverse',
|
||||
'transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 dark:ring-offset-0',
|
||||
{
|
||||
'text-gray-600 hover:text-gray-800 dark:hover:text-white bg-white hover:bg-primary-100 dark:hover:bg-primary-800 dark:bg-transparent black:hover:bg-gray-800': theme === 'default',
|
||||
'text-gray-600 hover:text-gray-800 dark:hover:text-white bg-transparent hover:bg-primary-100 dark:hover:bg-primary-800 black:hover:bg-gray-800': theme === 'default',
|
||||
'text-white/80 hover:text-white bg-transparent dark:bg-transparent': theme === 'inverse',
|
||||
'text-black dark:text-white': active && emoji,
|
||||
'hover:text-gray-600 dark:hover:text-white': !filteredProps.disabled,
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { useRouteMatch } from 'react-router-dom';
|
||||
|
||||
import { groupComposeModal } from 'soapbox/actions/compose';
|
||||
import { openModal } from 'soapbox/actions/modals';
|
||||
import { openSidebar } from 'soapbox/actions/sidebar';
|
||||
import ThumbNavigationLink from 'soapbox/components/thumb-navigation-link';
|
||||
import { useStatContext } from 'soapbox/contexts/stat-context';
|
||||
import { Entities } from 'soapbox/entity-store/entities';
|
||||
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
|
||||
|
||||
import { Icon } from './ui';
|
||||
|
@ -13,12 +17,24 @@ const ThumbNavigation: React.FC = (): JSX.Element => {
|
|||
const { account } = useOwnAccount();
|
||||
const features = useFeatures();
|
||||
|
||||
const match = useRouteMatch<{ groupId: string }>('/groups/:groupId');
|
||||
|
||||
const { unreadChatsCount } = useStatContext();
|
||||
|
||||
const notificationCount = useAppSelector((state) => state.notifications.unread);
|
||||
const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());
|
||||
|
||||
const onOpenSidebar = () => dispatch(openSidebar());
|
||||
const handleOpenSidebar = () => dispatch(openSidebar());
|
||||
|
||||
const handleOpenComposeModal = () => {
|
||||
if (match?.params.groupId) {
|
||||
dispatch((_, getState) => {
|
||||
const group = getState().entities[Entities.GROUPS]?.store[match.params.groupId];
|
||||
if (group) dispatch(groupComposeModal(group));
|
||||
});
|
||||
} else {
|
||||
dispatch(openModal('COMPOSE'));
|
||||
}
|
||||
};
|
||||
|
||||
/** Conditionally render the supported messages link */
|
||||
const renderMessagesLink = (): React.ReactNode => {
|
||||
|
@ -51,7 +67,7 @@ const ThumbNavigation: React.FC = (): JSX.Element => {
|
|||
|
||||
return (
|
||||
<div className='fixed inset-x-0 bottom-0 z-50 flex w-full overflow-x-auto border-t border-solid border-gray-200 bg-white/90 shadow-2xl backdrop-blur-md black:bg-black/80 lg:hidden dark:border-gray-800 dark:bg-primary-900/90'>
|
||||
<button className='flex flex-1 flex-col items-center px-2 py-4 text-lg text-gray-600' onClick={onOpenSidebar}>
|
||||
<button className='flex flex-1 flex-col items-center px-2 py-4 text-lg text-gray-600' onClick={handleOpenSidebar}>
|
||||
<Icon
|
||||
src={require('@tabler/icons/outline/menu-2.svg')}
|
||||
className='h-5 w-5 text-gray-600 black:text-white'
|
||||
|
@ -96,13 +112,13 @@ const ThumbNavigation: React.FC = (): JSX.Element => {
|
|||
|
||||
{account && renderMessagesLink()}
|
||||
|
||||
{(account && (account.is_admin || account.is_moderator)) && (
|
||||
<ThumbNavigationLink
|
||||
src={require('@tabler/icons/outline/dashboard.svg')}
|
||||
text={<FormattedMessage id='navigation.dashboard' defaultMessage='Dashboard' />}
|
||||
to='/soapbox/admin'
|
||||
count={dashboardCount}
|
||||
/>
|
||||
{account && (
|
||||
<button className='flex flex-1 flex-col items-center px-1.5 py-3.5 text-lg text-gray-600' onClick={handleOpenComposeModal}>
|
||||
<Icon
|
||||
src={require('@tabler/icons/outline/square-rounded-plus.svg')}
|
||||
className='h-6 w-6 text-gray-600 black:text-white'
|
||||
/>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -38,7 +38,6 @@ import { getVapidKey } from 'soapbox/utils/auth';
|
|||
import { isStandalone } from 'soapbox/utils/state';
|
||||
|
||||
import BackgroundShapes from './components/background-shapes';
|
||||
import FloatingActionButton from './components/floating-action-button';
|
||||
import {
|
||||
Status,
|
||||
CommunityTimeline,
|
||||
|
@ -444,11 +443,6 @@ const UI: React.FC<IUI> = ({ children }) => {
|
|||
dispatch(registerPushNotifications());
|
||||
}, [vapidKey]);
|
||||
|
||||
const shouldHideFAB = (): boolean => {
|
||||
const path = location.pathname;
|
||||
return Boolean(path.match(/^\/posts\/|^\/search|^\/getting-started|^\/chats/));
|
||||
};
|
||||
|
||||
// Wait for login to succeed or fail
|
||||
if (me === null) return null;
|
||||
|
||||
|
@ -478,12 +472,6 @@ const UI: React.FC<IUI> = ({ children }) => {
|
|||
</SwitchingColumnsArea>
|
||||
</Layout>
|
||||
|
||||
{(me && !shouldHideFAB()) && (
|
||||
<div className='fixed bottom-24 right-4 z-40 transition-all lg:hidden rtl:left-4 rtl:right-auto'>
|
||||
<FloatingActionButton />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Suspense>
|
||||
<SidebarMenu />
|
||||
</Suspense>
|
||||
|
|
Loading…
Reference in a new issue