pl-fe: layout changes for the deck
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -22,11 +22,12 @@ interface ISidebarNavigationLink {
|
||||
to?: string;
|
||||
/** Callback when the link is clicked. */
|
||||
onClick?: React.EventHandler<React.MouseEvent>;
|
||||
shrink?: boolean;
|
||||
}
|
||||
|
||||
/** Desktop sidebar navigation link. */
|
||||
const SidebarNavigationLink = React.memo(React.forwardRef((props: ISidebarNavigationLink, ref: React.ForwardedRef<HTMLAnchorElement>): JSX.Element => {
|
||||
const { icon, activeIcon, text, to = '', count, countMax, onClick } = props;
|
||||
const { icon, activeIcon, text, to = '', count, countMax, onClick, shrink } = props;
|
||||
const isActive = location.pathname === to;
|
||||
|
||||
const { demetricator } = useSettings();
|
||||
@ -69,7 +70,9 @@ const SidebarNavigationLink = React.memo(React.forwardRef((props: ISidebarNaviga
|
||||
/>
|
||||
</span>
|
||||
|
||||
<Text weight='semibold' theme='inherit'>{text}</Text>
|
||||
{!shrink && (
|
||||
<Text weight='semibold' theme='inherit'>{text}</Text>
|
||||
)}
|
||||
</NavLink>
|
||||
);
|
||||
}), (prevProps, nextProps) => prevProps.count === nextProps.count);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { useInfiniteQuery } from '@tanstack/react-query';
|
||||
import clsx from 'clsx';
|
||||
import React, { useMemo } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
@ -21,6 +22,7 @@ import DropdownMenu, { Menu } from './dropdown-menu';
|
||||
import SearchInput from './search-input';
|
||||
import SidebarNavigationLink from './sidebar-navigation-link';
|
||||
import SiteLogo from './site-logo';
|
||||
import Avatar from './ui/avatar';
|
||||
|
||||
const messages = defineMessages({
|
||||
followRequests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
||||
@ -36,8 +38,13 @@ const messages = defineMessages({
|
||||
interactionRequests: { id: 'navigation.interaction_requests', defaultMessage: 'Interaction requests' },
|
||||
});
|
||||
|
||||
interface ISidebarNavigation {
|
||||
/** Whether the sidebar is in shrinked mode. */
|
||||
shrink?: boolean;
|
||||
}
|
||||
|
||||
/** Desktop sidebar with links to different views in the app. */
|
||||
const SidebarNavigation = React.memo(() => {
|
||||
const SidebarNavigation: React.FC<ISidebarNavigation> = React.memo(({ shrink }) => {
|
||||
const intl = useIntl();
|
||||
const { unreadChatsCount } = useStatContext();
|
||||
|
||||
@ -161,24 +168,41 @@ const SidebarNavigation = React.memo(() => {
|
||||
}, [!!account, features, followRequestsCount, interactionRequestsCount, scheduledStatusCount, draftCount]);
|
||||
|
||||
return (
|
||||
<Stack space={4}>
|
||||
<SiteLogo className='h-12 w-auto cursor-pointer' />
|
||||
<Stack space={4} alignItems={shrink ? 'center' : undefined}>
|
||||
<SiteLogo
|
||||
className={clsx('h-12 w-auto cursor-pointer', {
|
||||
'max-w-10 h-auto': shrink,
|
||||
})}
|
||||
/>
|
||||
|
||||
{account && (
|
||||
<Stack space={4}>
|
||||
<div className='relative flex items-center'>
|
||||
<ProfileDropdown account={account}>
|
||||
<Account
|
||||
account={account}
|
||||
action={<Icon src={require('@tabler/icons/outline/chevron-down.svg')} className='text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-500' />}
|
||||
disabled
|
||||
withLinkToProfile={false}
|
||||
/>
|
||||
{shrink ? (
|
||||
<Avatar
|
||||
src={account.avatar}
|
||||
alt={account.avatar_description}
|
||||
isCat={account.is_cat}
|
||||
username={account.username}
|
||||
size={40}
|
||||
/>
|
||||
// className='size-10 bg-gray-50 ring-2 ring-white'
|
||||
) : (
|
||||
<Account
|
||||
account={account}
|
||||
action={<Icon src={require('@tabler/icons/outline/chevron-down.svg')} className='text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-500' />}
|
||||
disabled
|
||||
withLinkToProfile={false}
|
||||
/>
|
||||
)}
|
||||
</ProfileDropdown>
|
||||
</div>
|
||||
<div className='block w-full max-w-xs'>
|
||||
<SearchInput />
|
||||
</div>
|
||||
{!shrink && (
|
||||
<div className='block w-full max-w-xs'>
|
||||
<SearchInput />
|
||||
</div>
|
||||
)}
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
@ -188,12 +212,14 @@ const SidebarNavigation = React.memo(() => {
|
||||
icon={require('@tabler/icons/outline/home.svg')}
|
||||
activeIcon={require('@tabler/icons/filled/home.svg')}
|
||||
text={<FormattedMessage id='tabs_bar.home' defaultMessage='Home' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
|
||||
<SidebarNavigationLink
|
||||
to='/search'
|
||||
icon={require('@tabler/icons/outline/search.svg')}
|
||||
text={<FormattedMessage id='tabs_bar.search' defaultMessage='Search' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
|
||||
{account && (
|
||||
@ -204,6 +230,7 @@ const SidebarNavigation = React.memo(() => {
|
||||
activeIcon={require('@tabler/icons/filled/bell.svg')}
|
||||
count={notificationCount}
|
||||
text={<FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
|
||||
{features.chats && (
|
||||
@ -213,6 +240,7 @@ const SidebarNavigation = React.memo(() => {
|
||||
count={unreadChatsCount}
|
||||
countMax={9}
|
||||
text={<FormattedMessage id='navigation.chats' defaultMessage='Chats' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -222,6 +250,7 @@ const SidebarNavigation = React.memo(() => {
|
||||
icon={require('@tabler/icons/outline/mail.svg')}
|
||||
activeIcon={require('@tabler/icons/filled/mail.svg')}
|
||||
text={<FormattedMessage id='navigation.direct_messages' defaultMessage='Direct messages' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -231,6 +260,7 @@ const SidebarNavigation = React.memo(() => {
|
||||
icon={require('@tabler/icons/outline/circles.svg')}
|
||||
activeIcon={require('@tabler/icons/filled/circles.svg')}
|
||||
text={<FormattedMessage id='tabs_bar.groups' defaultMessage='Groups' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -239,6 +269,7 @@ const SidebarNavigation = React.memo(() => {
|
||||
icon={require('@tabler/icons/outline/user.svg')}
|
||||
activeIcon={require('@tabler/icons/filled/user.svg')}
|
||||
text={<FormattedMessage id='tabs_bar.profile' defaultMessage='Profile' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
|
||||
<SidebarNavigationLink
|
||||
@ -246,6 +277,7 @@ const SidebarNavigation = React.memo(() => {
|
||||
icon={require('@tabler/icons/outline/settings.svg')}
|
||||
activeIcon={require('@tabler/icons/filled/settings.svg')}
|
||||
text={<FormattedMessage id='tabs_bar.settings' defaultMessage='Settings' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
|
||||
{(account.is_admin || account.is_moderator) && (
|
||||
@ -254,6 +286,7 @@ const SidebarNavigation = React.memo(() => {
|
||||
icon={require('@tabler/icons/outline/dashboard.svg')}
|
||||
count={dashboardCount}
|
||||
text={<FormattedMessage id='tabs_bar.dashboard' defaultMessage='Dashboard' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
@ -267,6 +300,7 @@ const SidebarNavigation = React.memo(() => {
|
||||
icon={features.federating ? require('@tabler/icons/outline/affiliate.svg') : require('@tabler/icons/outline/world.svg')}
|
||||
activeIcon={features.federating ? require('@tabler/icons/filled/affiliate.svg') : undefined}
|
||||
text={features.federating ? <FormattedMessage id='tabs_bar.local' defaultMessage='Local' /> : <FormattedMessage id='tabs_bar.all' defaultMessage='All' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -276,6 +310,7 @@ const SidebarNavigation = React.memo(() => {
|
||||
icon={require('@tabler/icons/outline/chart-bubble.svg')}
|
||||
activeIcon={require('@tabler/icons/filled/chart-bubble.svg')}
|
||||
text={<FormattedMessage id='tabs_bar.bubble' defaultMessage='Bubble' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -284,6 +319,7 @@ const SidebarNavigation = React.memo(() => {
|
||||
to='/timeline/fediverse'
|
||||
icon={require('@tabler/icons/outline/topology-star-ring-3.svg')}
|
||||
text={<FormattedMessage id='tabs_bar.fediverse' defaultMessage='Fediverse' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
@ -294,6 +330,7 @@ const SidebarNavigation = React.memo(() => {
|
||||
<SidebarNavigationLink
|
||||
icon={require('@tabler/icons/outline/dots-circle-horizontal.svg')}
|
||||
text={<FormattedMessage id='tabs_bar.more' defaultMessage='More' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
@ -304,19 +341,21 @@ const SidebarNavigation = React.memo(() => {
|
||||
to='/login'
|
||||
icon={require('@tabler/icons/outline/login.svg')}
|
||||
text={<FormattedMessage id='account.login' defaultMessage='Log in' />}
|
||||
shrink={shrink}
|
||||
/>
|
||||
|
||||
{isOpen && <SidebarNavigationLink
|
||||
to='/signup'
|
||||
icon={require('@tabler/icons/outline/user-plus.svg')}
|
||||
text={<FormattedMessage id='account.register' defaultMessage='Sign up' />}
|
||||
shrink={shrink}
|
||||
/>}
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
{account && (
|
||||
<ComposeButton />
|
||||
<ComposeButton shrink={shrink} />
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@ -6,6 +6,7 @@ import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
|
||||
interface ISidebar {
|
||||
children: React.ReactNode;
|
||||
shrink?: boolean;
|
||||
}
|
||||
interface IAside {
|
||||
children?: React.ReactNode;
|
||||
@ -13,6 +14,7 @@ interface IAside {
|
||||
|
||||
interface ILayout {
|
||||
children: React.ReactNode;
|
||||
fullWidth?: boolean;
|
||||
}
|
||||
|
||||
interface LayoutComponent extends React.FC<ILayout> {
|
||||
@ -22,17 +24,25 @@ interface LayoutComponent extends React.FC<ILayout> {
|
||||
}
|
||||
|
||||
/** Layout container, to hold Sidebar, Main, and Aside. */
|
||||
const Layout: LayoutComponent = ({ children }) => (
|
||||
const Layout: LayoutComponent = ({ children, fullWidth }) => (
|
||||
<div className='relative flex grow flex-col black:pt-0 sm:pt-4'>
|
||||
<div className='mx-auto w-full max-w-3xl grow sm:px-6 md:grid md:max-w-7xl md:grid-cols-12 md:gap-8 md:px-8 xl:max-w-[1440px]'>
|
||||
<div
|
||||
className={clsx(
|
||||
'mx-auto w-full max-w-3xl grow sm:px-6 md:gap-8 md:px-8',
|
||||
{
|
||||
'flex md:max-w-full': fullWidth,
|
||||
'md:grid md:max-w-7xl md:grid-cols-12 xl:max-w-[1440px]': !fullWidth,
|
||||
},
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
/** Left sidebar container in the UI. */
|
||||
const Sidebar: React.FC<ISidebar> = ({ children }) => (
|
||||
<div className='hidden lg:col-span-3 lg:block'>
|
||||
const Sidebar: React.FC<ISidebar> = ({ children, shrink }) => (
|
||||
<div className={clsx('hidden lg:block', { 'lg:col-span-3': !shrink, 'w-fit': shrink })}>
|
||||
<StickyBox offsetTop={16} className='pb-4'>
|
||||
{children}
|
||||
</StickyBox>
|
||||
|
||||
@ -10,7 +10,12 @@ import HStack from 'pl-fe/components/ui/hstack';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
|
||||
const ComposeButton = () => {
|
||||
interface IComposeButton {
|
||||
/** Whether the button should shrink to fit in a smaller space. */
|
||||
shrink?: boolean;
|
||||
}
|
||||
|
||||
const ComposeButton: React.FC<IComposeButton> = ({ shrink }) => {
|
||||
const location = useLocation();
|
||||
const isOnGroupPage = location.pathname.startsWith('/group/');
|
||||
const match = useRouteMatch<{ groupId: string }>('/groups/:groupId');
|
||||
@ -18,13 +23,13 @@ const ComposeButton = () => {
|
||||
const isGroupMember = !!group?.relationship?.member;
|
||||
|
||||
if (isOnGroupPage && isGroupMember) {
|
||||
return <GroupComposeButton />;
|
||||
return <GroupComposeButton shrink={shrink} />;
|
||||
}
|
||||
|
||||
return <HomeComposeButton />;
|
||||
return <HomeComposeButton shrink={shrink} />;
|
||||
};
|
||||
|
||||
const HomeComposeButton = () => {
|
||||
const HomeComposeButton: React.FC<IComposeButton> = ({ shrink }) => {
|
||||
const { openModal } = useModalsStore();
|
||||
const onOpenCompose = () => openModal('COMPOSE');
|
||||
|
||||
@ -34,13 +39,16 @@ const HomeComposeButton = () => {
|
||||
size='lg'
|
||||
onClick={onOpenCompose}
|
||||
block
|
||||
icon={shrink ? require('@tabler/icons/outline/plus.svg') : undefined}
|
||||
>
|
||||
<FormattedMessage id='navigation.compose' defaultMessage='Compose' />
|
||||
{!shrink && (
|
||||
<FormattedMessage id='navigation.compose' defaultMessage='Compose' />
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
const GroupComposeButton = () => {
|
||||
const GroupComposeButton: React.FC<IComposeButton> = ({ shrink }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const match = useRouteMatch<{ groupId: string }>('/groups/:groupId');
|
||||
const { group } = useGroup(match?.params.groupId || '');
|
||||
@ -57,13 +65,16 @@ const GroupComposeButton = () => {
|
||||
size='lg'
|
||||
onClick={onOpenCompose}
|
||||
block
|
||||
icon={shrink ? require('@tabler/icons/outline/plus.svg') : undefined}
|
||||
>
|
||||
<HStack space={3} alignItems='center'>
|
||||
<Avatar className='-my-1 border-2 border-white' size={30} src={group.avatar} alt={group.avatar_description} />
|
||||
<span>
|
||||
<FormattedMessage id='navigation.compose_group' defaultMessage='Compose to group' />
|
||||
</span>
|
||||
</HStack>
|
||||
{!shrink && (
|
||||
<HStack space={3} alignItems='center'>
|
||||
<Avatar className='-my-1 border-2 border-white' size={30} src={group.avatar} alt={group.avatar_description} />
|
||||
<span>
|
||||
<FormattedMessage id='navigation.compose_group' defaultMessage='Compose to group' />
|
||||
</span>
|
||||
</HStack>
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
@ -488,6 +488,9 @@ const UI: React.FC<IUI> = React.memo(({ children }) => {
|
||||
pointerEvents: isDropdownMenuOpen ? 'none' : undefined,
|
||||
};
|
||||
|
||||
// to be used with the deck
|
||||
const fullWidth = false;
|
||||
|
||||
return (
|
||||
<GlobalHotkeys node={node}>
|
||||
<div ref={node} style={style}>
|
||||
@ -500,9 +503,9 @@ const UI: React.FC<IUI> = React.memo(({ children }) => {
|
||||
<BackgroundShapes />
|
||||
|
||||
<div className='z-10 flex min-h-screen flex-col'>
|
||||
<Layout>
|
||||
<Layout.Sidebar>
|
||||
{!(standalone && !me) && <SidebarNavigation />}
|
||||
<Layout fullWidth={fullWidth}>
|
||||
<Layout.Sidebar shrink={fullWidth}>
|
||||
{!(standalone && !me) && <SidebarNavigation shrink={fullWidth} />}
|
||||
</Layout.Sidebar>
|
||||
|
||||
<SwitchingColumnsArea>
|
||||
|
||||
@ -6,7 +6,7 @@ interface IChatsLayout {
|
||||
|
||||
/** Custom layout for chats on desktop. */
|
||||
const ChatsLayout: React.FC<IChatsLayout> = ({ children }) => (
|
||||
<div className='black:border-gray-800 md:col-span-12 lg:col-span-9 lg:black:border-l'>
|
||||
<div className='grow black:border-gray-800 md:col-span-12 lg:col-span-9 lg:black:border-l'>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user