Condense feeds on mobile
This commit is contained in:
parent
8161cfbdec
commit
78be563bdc
|
@ -12,6 +12,7 @@ import PullToRefresh from 'soapbox/components/pull-to-refresh';
|
|||
import StatusList from 'soapbox/components/status-list';
|
||||
import { Column } from 'soapbox/components/ui';
|
||||
import { useAppSelector, useAppDispatch, useTheme } from 'soapbox/hooks';
|
||||
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
||||
import toast from 'soapbox/toast';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
@ -40,6 +41,7 @@ const Bookmarks: React.FC<IBookmarks> = ({ params }) => {
|
|||
const intl = useIntl();
|
||||
const history = useHistory();
|
||||
const theme = useTheme();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const folderId = params?.id;
|
||||
|
||||
|
@ -106,7 +108,7 @@ const Bookmarks: React.FC<IBookmarks> = ({ params }) => {
|
|||
action={
|
||||
<DropdownMenu items={items} src={require('@tabler/icons/outline/dots-vertical.svg')} />
|
||||
}
|
||||
transparent
|
||||
transparent={!isMobile}
|
||||
>
|
||||
<PullToRefresh onRefresh={handleRefresh}>
|
||||
<StatusList
|
||||
|
@ -117,7 +119,7 @@ const Bookmarks: React.FC<IBookmarks> = ({ params }) => {
|
|||
isLoading={typeof isLoading === 'boolean' ? isLoading : true}
|
||||
onLoadMore={() => handleLoadMore(dispatch, folderId)}
|
||||
emptyMessage={emptyMessage}
|
||||
divideType={theme === 'black' ? 'border' : 'space'}
|
||||
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
|
||||
/>
|
||||
</PullToRefresh>
|
||||
</Column>
|
||||
|
|
|
@ -6,6 +6,7 @@ import { useCommunityStream } from 'soapbox/api/hooks';
|
|||
import PullToRefresh from 'soapbox/components/pull-to-refresh';
|
||||
import { Column } from 'soapbox/components/ui';
|
||||
import { useAppSelector, useAppDispatch, useSettings, useTheme } from 'soapbox/hooks';
|
||||
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
||||
|
||||
import Timeline from '../ui/components/timeline';
|
||||
|
||||
|
@ -23,6 +24,7 @@ const CommunityTimeline = () => {
|
|||
const next = useAppSelector(state => state.timelines.get('community')?.next);
|
||||
|
||||
const timelineId = 'community';
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const handleLoadMore = (maxId: string) => {
|
||||
dispatch(expandCommunityTimeline({ url: next, maxId, onlyMedia }));
|
||||
|
@ -39,7 +41,7 @@ const CommunityTimeline = () => {
|
|||
}, [onlyMedia]);
|
||||
|
||||
return (
|
||||
<Column className='-mt-3 sm:mt-0' label={intl.formatMessage(messages.title)} transparent>
|
||||
<Column className='-mt-3 sm:mt-0' label={intl.formatMessage(messages.title)} transparent={!isMobile}>
|
||||
<PullToRefresh onRefresh={handleRefresh}>
|
||||
<Timeline
|
||||
className='black:p-4 black:sm:p-5'
|
||||
|
@ -48,7 +50,7 @@ const CommunityTimeline = () => {
|
|||
prefix='home'
|
||||
onLoadMore={handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
|
||||
divideType={theme === 'black' ? 'border' : 'space'}
|
||||
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
|
||||
/>
|
||||
</PullToRefresh>
|
||||
</Column>
|
||||
|
|
|
@ -8,6 +8,7 @@ import List, { ListItem } from 'soapbox/components/list';
|
|||
import { Column, Toggle } from 'soapbox/components/ui';
|
||||
import Timeline from 'soapbox/features/ui/components/timeline';
|
||||
import { useAppDispatch, useAppSelector, useFeatures, useLoggedIn, useTheme } from 'soapbox/hooks';
|
||||
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
||||
|
||||
interface IHashtagTimeline {
|
||||
params?: {
|
||||
|
@ -24,6 +25,7 @@ export const HashtagTimeline: React.FC<IHashtagTimeline> = ({ params }) => {
|
|||
const next = useAppSelector(state => state.timelines.get(`hashtag:${id}`)?.next);
|
||||
const { isLoggedIn } = useLoggedIn();
|
||||
const theme = useTheme();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const handleLoadMore = (maxId: string) => {
|
||||
dispatch(expandHashtagTimeline(id, { url: next, maxId }));
|
||||
|
@ -50,7 +52,7 @@ export const HashtagTimeline: React.FC<IHashtagTimeline> = ({ params }) => {
|
|||
}, [id]);
|
||||
|
||||
return (
|
||||
<Column label={`#${id}`} transparent>
|
||||
<Column label={`#${id}`} transparent={!isMobile}>
|
||||
{features.followHashtags && isLoggedIn && (
|
||||
<List>
|
||||
<ListItem
|
||||
|
@ -69,7 +71,7 @@ export const HashtagTimeline: React.FC<IHashtagTimeline> = ({ params }) => {
|
|||
timelineId={`hashtag:${id}`}
|
||||
onLoadMore={handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />}
|
||||
divideType={theme === 'black' ? 'border' : 'space'}
|
||||
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
|
|
|
@ -7,6 +7,7 @@ import PullToRefresh from 'soapbox/components/pull-to-refresh';
|
|||
import { Column, Stack, Text } from 'soapbox/components/ui';
|
||||
import Timeline from 'soapbox/features/ui/components/timeline';
|
||||
import { useAppSelector, useAppDispatch, useFeatures, useInstance, useTheme } from 'soapbox/hooks';
|
||||
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.home', defaultMessage: 'Home' },
|
||||
|
@ -20,6 +21,7 @@ const HomeTimeline: React.FC = () => {
|
|||
const theme = useTheme();
|
||||
|
||||
const polling = useRef<NodeJS.Timeout | null>(null);
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const isPartial = useAppSelector(state => state.timelines.get('home')?.isPartial === true);
|
||||
const next = useAppSelector(state => state.timelines.get('home')?.next);
|
||||
|
@ -60,14 +62,14 @@ const HomeTimeline: React.FC = () => {
|
|||
}, [isPartial]);
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.title)} transparent withHeader={false}>
|
||||
<Column label={intl.formatMessage(messages.title)} transparent={!isMobile} withHeader={false}>
|
||||
<PullToRefresh onRefresh={handleRefresh}>
|
||||
<Timeline
|
||||
className='black:p-4 black:sm:p-5'
|
||||
scrollKey='home_timeline'
|
||||
onLoadMore={handleLoadMore}
|
||||
timelineId='home'
|
||||
divideType={theme === 'black' ? 'border' : 'space'}
|
||||
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
|
||||
showAds
|
||||
emptyMessage={
|
||||
<Stack space={1}>
|
||||
|
|
|
@ -6,6 +6,7 @@ import { useCommunityStream } from 'soapbox/api/hooks';
|
|||
import PullToRefresh from 'soapbox/components/pull-to-refresh';
|
||||
import { Column } from 'soapbox/components/ui';
|
||||
import { useAppSelector, useAppDispatch, useInstance, useTheme } from 'soapbox/hooks';
|
||||
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
||||
|
||||
import AboutPage from '../about';
|
||||
import Timeline from '../ui/components/timeline';
|
||||
|
@ -16,6 +17,7 @@ const LandingTimeline = () => {
|
|||
const dispatch = useAppDispatch();
|
||||
const instance = useInstance();
|
||||
const theme = useTheme();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const timelineEnabled = !instance.pleroma.metadata.restrict_unauthenticated.timelines.local;
|
||||
const next = useAppSelector(state => state.timelines.get('community')?.next);
|
||||
|
@ -43,7 +45,7 @@ const LandingTimeline = () => {
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<Column transparent withHeader={false}>
|
||||
<Column transparent={!isMobile} withHeader={false}>
|
||||
<div className='my-12 mb-16 px-4 sm:mb-20'>
|
||||
<SiteBanner />
|
||||
</div>
|
||||
|
@ -57,7 +59,7 @@ const LandingTimeline = () => {
|
|||
prefix='home'
|
||||
onLoadMore={handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
|
||||
divideType={theme === 'black' ? 'border' : 'space'}
|
||||
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
|
||||
/>
|
||||
</PullToRefresh>
|
||||
) : (
|
||||
|
|
|
@ -9,6 +9,7 @@ import { useListStream } from 'soapbox/api/hooks';
|
|||
import MissingIndicator from 'soapbox/components/missing-indicator';
|
||||
import { Column, Button, Spinner } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useAppSelector, useTheme } from 'soapbox/hooks';
|
||||
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
||||
|
||||
import Timeline from '../ui/components/timeline';
|
||||
|
||||
|
@ -16,6 +17,7 @@ const ListTimeline: React.FC = () => {
|
|||
const dispatch = useAppDispatch();
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const theme = useTheme();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const list = useAppSelector((state) => state.lists.get(id));
|
||||
const next = useAppSelector(state => state.timelines.get(`list:${id}`)?.next);
|
||||
|
@ -60,14 +62,14 @@ const ListTimeline: React.FC = () => {
|
|||
);
|
||||
|
||||
return (
|
||||
<Column label={title} transparent>
|
||||
<Column label={title} transparent={!isMobile}>
|
||||
<Timeline
|
||||
className='black:p-4 black:sm:p-5'
|
||||
scrollKey='list_timeline'
|
||||
timelineId={`list:${id}`}
|
||||
onLoadMore={handleLoadMore}
|
||||
emptyMessage={emptyMessage}
|
||||
divideType={theme === 'black' ? 'border' : 'space'}
|
||||
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
|
|
|
@ -8,6 +8,7 @@ import { usePublicStream } from 'soapbox/api/hooks';
|
|||
import PullToRefresh from 'soapbox/components/pull-to-refresh';
|
||||
import { Accordion, Column } from 'soapbox/components/ui';
|
||||
import { useAppSelector, useAppDispatch, useInstance, useSettings, useTheme, useFeatures } from 'soapbox/hooks';
|
||||
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
||||
|
||||
import PinnedHostsPicker from '../remote-timeline/components/pinned-hosts-picker';
|
||||
import Timeline from '../ui/components/timeline';
|
||||
|
@ -29,6 +30,7 @@ const PublicTimeline = () => {
|
|||
const next = useAppSelector(state => state.timelines.get('public')?.next);
|
||||
|
||||
const timelineId = 'public';
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const explanationBoxExpanded = settings.explanationBox;
|
||||
const showExplanationBox = settings.showExplanationBox && !features.nostr;
|
||||
|
@ -56,7 +58,7 @@ const PublicTimeline = () => {
|
|||
}, [onlyMedia]);
|
||||
|
||||
return (
|
||||
<Column className='-mt-3 sm:mt-0' label={intl.formatMessage(messages.title)} transparent>
|
||||
<Column className='-mt-3 sm:mt-0' label={intl.formatMessage(messages.title)} transparent={!isMobile}>
|
||||
<PinnedHostsPicker />
|
||||
|
||||
{showExplanationBox && (
|
||||
|
@ -96,7 +98,7 @@ const PublicTimeline = () => {
|
|||
prefix='home'
|
||||
onLoadMore={handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other servers to fill it up' />}
|
||||
divideType={theme === 'black' ? 'border' : 'space'}
|
||||
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
|
||||
/>
|
||||
</PullToRefresh>
|
||||
</Column>
|
||||
|
|
|
@ -8,6 +8,7 @@ import { expandStatusQuotes, fetchStatusQuotes } from 'soapbox/actions/status-qu
|
|||
import StatusList from 'soapbox/components/status-list';
|
||||
import { Column } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useAppSelector, useTheme } from 'soapbox/hooks';
|
||||
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.quotes', defaultMessage: 'Post quotes' },
|
||||
|
@ -21,6 +22,7 @@ const Quotes: React.FC = () => {
|
|||
const intl = useIntl();
|
||||
const { statusId } = useParams<{ statusId: string }>();
|
||||
const theme = useTheme();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const statusIds = useAppSelector((state) => state.status_lists.getIn([`quotes:${statusId}`, 'items'], ImmutableOrderedSet<string>()));
|
||||
const isLoading = useAppSelector((state) => state.status_lists.getIn([`quotes:${statusId}`, 'isLoading'], true));
|
||||
|
@ -37,7 +39,7 @@ const Quotes: React.FC = () => {
|
|||
const emptyMessage = <FormattedMessage id='empty_column.quotes' defaultMessage='This post has not been quoted yet.' />;
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.heading)} transparent>
|
||||
<Column label={intl.formatMessage(messages.heading)} transparent={!isMobile}>
|
||||
<StatusList
|
||||
className='black:p-4 black:sm:p-5'
|
||||
statusIds={statusIds as ImmutableOrderedSet<string>}
|
||||
|
@ -47,7 +49,7 @@ const Quotes: React.FC = () => {
|
|||
onLoadMore={() => handleLoadMore(statusId, dispatch)}
|
||||
onRefresh={handleRefresh}
|
||||
emptyMessage={emptyMessage}
|
||||
divideType={theme === 'black' ? 'border' : 'space'}
|
||||
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
|
|
|
@ -7,6 +7,7 @@ import { useRemoteStream } from 'soapbox/api/hooks';
|
|||
import IconButton from 'soapbox/components/icon-button';
|
||||
import { Column, HStack, Text } from 'soapbox/components/ui';
|
||||
import { useAppSelector, useAppDispatch, useSettings, useTheme } from 'soapbox/hooks';
|
||||
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
||||
|
||||
import Timeline from '../ui/components/timeline';
|
||||
|
||||
|
@ -32,6 +33,7 @@ const RemoteTimeline: React.FC<IRemoteTimeline> = ({ params }) => {
|
|||
const next = useAppSelector(state => state.timelines.get('remote')?.next);
|
||||
|
||||
const pinned = settings.remote_timeline.pinnedHosts.includes(instance);
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const handleCloseClick: React.MouseEventHandler = () => {
|
||||
history.push('/timeline/fediverse');
|
||||
|
@ -48,7 +50,7 @@ const RemoteTimeline: React.FC<IRemoteTimeline> = ({ params }) => {
|
|||
}, [onlyMedia]);
|
||||
|
||||
return (
|
||||
<Column label={instance} transparent>
|
||||
<Column label={instance} transparent={!isMobile}>
|
||||
{instance && <PinnedHostsPicker host={instance} />}
|
||||
|
||||
{!pinned && (
|
||||
|
@ -76,7 +78,7 @@ const RemoteTimeline: React.FC<IRemoteTimeline> = ({ params }) => {
|
|||
values={{ instance }}
|
||||
/>
|
||||
}
|
||||
divideType={theme === 'black' ? 'border' : 'space'}
|
||||
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
|
|
|
@ -4,6 +4,7 @@ import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
|||
import { importFetchedStatuses } from 'soapbox/actions/importer';
|
||||
import { expandTimelineSuccess } from 'soapbox/actions/timelines';
|
||||
import { useAppDispatch, useTheme } from 'soapbox/hooks';
|
||||
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
||||
|
||||
import { Column } from '../../components/ui';
|
||||
import Timeline from '../ui/components/timeline';
|
||||
|
@ -32,6 +33,7 @@ const TestTimeline: React.FC = () => {
|
|||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
const theme = useTheme();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatch(importFetchedStatuses(MOCK_STATUSES));
|
||||
|
@ -39,12 +41,12 @@ const TestTimeline: React.FC = () => {
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.title)} transparent>
|
||||
<Column label={intl.formatMessage(messages.title)} transparent={!isMobile}>
|
||||
<Timeline
|
||||
scrollKey={`${timelineId}_timeline`}
|
||||
timelineId={`${timelineId}${onlyMedia ? ':media' : ''}`}
|
||||
emptyMessage={<FormattedMessage id='empty_column.test' defaultMessage='The test timeline is empty.' />}
|
||||
divideType={theme === 'black' ? 'border' : 'space'}
|
||||
divideType={(theme === 'black' || isMobile) ? 'border' : 'space'}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
|
|
|
@ -11,6 +11,7 @@ import SiteLogo from 'soapbox/components/site-logo';
|
|||
import { Avatar, Button, Form, HStack, IconButton, Input, Tooltip } from 'soapbox/components/ui';
|
||||
import Search from 'soapbox/features/compose/components/search';
|
||||
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount, useRegistrationStatus } from 'soapbox/hooks';
|
||||
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
||||
import { isStandalone } from 'soapbox/utils/state';
|
||||
|
||||
import ProfileDropdown from './profile-dropdown';
|
||||
|
@ -33,6 +34,7 @@ const Navbar = () => {
|
|||
const { isOpen } = useRegistrationStatus();
|
||||
const { account } = useOwnAccount();
|
||||
const node = useRef(null);
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const [isLoading, setLoading] = useState<boolean>(false);
|
||||
const [username, setUsername] = useState<string>('');
|
||||
|
@ -72,7 +74,14 @@ const Navbar = () => {
|
|||
if (mfaToken) return <Redirect to={`/login?token=${encodeURIComponent(mfaToken)}`} />;
|
||||
|
||||
return (
|
||||
<nav className='sticky top-0 z-50 bg-white shadow black:border-b black:border-b-gray-800 black:bg-black dark:bg-primary-900' ref={node} data-testid='navbar'>
|
||||
<nav
|
||||
className={clsx(
|
||||
'sticky top-0 z-50 border-gray-200 bg-white shadow black:border-b black:border-b-gray-800 black:bg-black dark:border-gray-800 dark:bg-primary-900',
|
||||
{ 'border-b': isMobile },
|
||||
)}
|
||||
ref={node}
|
||||
data-testid='navbar'
|
||||
>
|
||||
<div className='mx-auto max-w-7xl px-2 sm:px-6 lg:px-8'>
|
||||
<div className='relative flex h-12 justify-between lg:h-16'>
|
||||
{account && (
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import { useScreenWidth } from './useScreenWidth';
|
||||
|
||||
export function useIsMobile() {
|
||||
const screenWidth = useScreenWidth();
|
||||
return screenWidth <= 581;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
|
||||
export function useScreenWidth() {
|
||||
const [screenWidth, setScreenWidth] = useState(window.innerWidth);
|
||||
|
||||
useEffect(() => {
|
||||
const checkWindowSize = () => {
|
||||
setScreenWidth(window.innerWidth);
|
||||
};
|
||||
|
||||
window.addEventListener('resize', checkWindowSize);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', checkWindowSize);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return screenWidth;
|
||||
}
|
|
@ -17,6 +17,7 @@ import {
|
|||
AnnouncementsPanel,
|
||||
} from 'soapbox/features/ui/util/async-components';
|
||||
import { useAppSelector, useOwnAccount, useFeatures, useSoapboxConfig, useDraggedFiles, useAppDispatch } from 'soapbox/hooks';
|
||||
import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
||||
|
||||
import { Avatar, Card, CardBody, HStack, Layout } from '../components/ui';
|
||||
import ComposeForm from '../features/compose/components/compose-form';
|
||||
|
@ -36,6 +37,7 @@ const HomePage: React.FC<IHomePage> = ({ children }) => {
|
|||
|
||||
const composeId = 'home';
|
||||
const composeBlock = useRef<HTMLDivElement>(null);
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const hasPatron = soapboxConfig.extensions.getIn(['patron', 'enabled']) === true;
|
||||
const hasCrypto = typeof soapboxConfig.cryptoAddresses.getIn([0, 'ticker']) === 'string';
|
||||
|
@ -50,12 +52,13 @@ const HomePage: React.FC<IHomePage> = ({ children }) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Layout.Main className='space-y-3 pt-3 black:space-y-0 sm:pt-0 dark:divide-gray-800'>
|
||||
<Layout.Main className={clsx('black:space-y-0 dark:divide-gray-800', { 'pt-3 sm:pt-0 space-y-3': !isMobile })}>
|
||||
{me && (
|
||||
<Card
|
||||
className={clsx('relative z-[1] transition black:border-b black:border-gray-800', {
|
||||
className={clsx('relative z-[1] border-gray-200 transition black:border-b black:border-gray-800 dark:border-gray-800', {
|
||||
'border-2 border-primary-600 border-dashed z-[99]': isDragging,
|
||||
'ring-2 ring-offset-2 ring-primary-600': isDraggedOver,
|
||||
'border-b': isMobile,
|
||||
})}
|
||||
variant='rounded'
|
||||
ref={composeBlock}
|
||||
|
|
Loading…
Reference in New Issue