Merge remote-tracking branch 'origin/develop' into chat-composer
This commit is contained in:
commit
25277b0b73
204 changed files with 1535 additions and 1264 deletions
|
@ -5,6 +5,7 @@ module.exports = {
|
|||
'eslint:recommended',
|
||||
'plugin:import/typescript',
|
||||
'plugin:compat/recommended',
|
||||
'plugin:tailwindcss/recommended',
|
||||
],
|
||||
|
||||
env: {
|
||||
|
@ -61,6 +62,9 @@ module.exports = {
|
|||
'URL', // core-js
|
||||
'URLSearchParams', // core-js
|
||||
],
|
||||
tailwindcss: {
|
||||
config: 'tailwind.config.cjs',
|
||||
},
|
||||
},
|
||||
|
||||
rules: {
|
||||
|
@ -235,18 +239,7 @@ module.exports = {
|
|||
},
|
||||
],
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
// {
|
||||
// devDependencies: [
|
||||
// 'webpack/**',
|
||||
// 'app/soapbox/test_setup.js',
|
||||
// 'app/soapbox/test_helpers.js',
|
||||
// 'app/**/__tests__/**',
|
||||
// 'app/**/__mocks__/**',
|
||||
// ],
|
||||
// },
|
||||
],
|
||||
'import/no-extraneous-dependencies': 'error',
|
||||
'import/no-unresolved': 'error',
|
||||
'import/no-webpack-loader-syntax': 'error',
|
||||
'import/order': [
|
||||
|
@ -271,6 +264,9 @@ module.exports = {
|
|||
'promise/catch-or-return': 'error',
|
||||
|
||||
'react-hooks/rules-of-hooks': 'error',
|
||||
|
||||
'tailwindcss/classnames-order': 'error',
|
||||
'tailwindcss/migration-from-tailwind-2': 'error',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
|
|
|
@ -149,9 +149,9 @@ pages:
|
|||
|
||||
docker:
|
||||
stage: deploy
|
||||
image: docker:20.10.23
|
||||
image: docker:23.0.0
|
||||
services:
|
||||
- docker:20.10.23-dind
|
||||
- docker:23.0.0-dind
|
||||
tags:
|
||||
- dind
|
||||
# https://medium.com/devops-with-valentine/how-to-build-a-docker-image-and-push-it-to-the-gitlab-container-registry-from-a-gitlab-ci-pipeline-acac0d1f26df
|
||||
|
|
|
@ -1 +1 @@
|
|||
nodejs 18.13.0
|
||||
nodejs 18.14.0
|
||||
|
|
|
@ -72,7 +72,7 @@ const AccountSearch: React.FC<IAccountSearch> = ({ onSelected, ...rest }) => {
|
|||
<div
|
||||
role='button'
|
||||
tabIndex={0}
|
||||
className='absolute inset-y-0 right-0 px-3 flex items-center cursor-pointer'
|
||||
className='absolute inset-y-0 right-0 flex cursor-pointer items-center px-3'
|
||||
onClick={handleClear}
|
||||
>
|
||||
<SvgIcon
|
||||
|
|
|
@ -43,11 +43,11 @@ const InstanceFavicon: React.FC<IInstanceFavicon> = ({ account, disabled }) => {
|
|||
|
||||
return (
|
||||
<button
|
||||
className='w-4 h-4 flex-none focus:ring-primary-500 focus:ring-2 focus:ring-offset-2'
|
||||
className='h-4 w-4 flex-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2'
|
||||
onClick={handleClick}
|
||||
disabled={disabled}
|
||||
>
|
||||
<img src={account.favicon} alt='' title={account.domain} className='w-full max-h-full' />
|
||||
<img src={account.favicon} alt='' title={account.domain} className='max-h-full w-full' />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
@ -147,7 +147,7 @@ const Account = ({
|
|||
src={actionIcon}
|
||||
title={actionTitle}
|
||||
onClick={handleAction}
|
||||
className='bg-transparent text-gray-600 dark:text-gray-600 hover:text-gray-700 dark:hover:text-gray-500'
|
||||
className='bg-transparent text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-500'
|
||||
iconClassName='w-4 h-4'
|
||||
/>
|
||||
);
|
||||
|
@ -193,7 +193,7 @@ const Account = ({
|
|||
const LinkEl: any = withLinkToProfile ? Link : 'div';
|
||||
|
||||
return (
|
||||
<div data-testid='account' className='flex-shrink-0 group block w-full' ref={overflowRef}>
|
||||
<div data-testid='account' className='group block w-full shrink-0' ref={overflowRef}>
|
||||
<HStack alignItems={actionAlignment} justifyContent='between'>
|
||||
<HStack alignItems={withAccountNote || note ? 'top' : 'center'} space={3}>
|
||||
<ProfilePopper
|
||||
|
@ -208,14 +208,14 @@ const Account = ({
|
|||
<Avatar src={account.avatar} size={avatarSize} />
|
||||
{emoji && (
|
||||
<Emoji
|
||||
className='w-5 h-5 absolute -bottom-1.5 -right-1.5'
|
||||
className='absolute -bottom-1.5 -right-1.5 h-5 w-5'
|
||||
emoji={emoji}
|
||||
/>
|
||||
)}
|
||||
</LinkEl>
|
||||
</ProfilePopper>
|
||||
|
||||
<div className='flex-grow'>
|
||||
<div className='grow'>
|
||||
<ProfilePopper
|
||||
condition={showProfileHoverCard}
|
||||
wrapper={(children) => <HoverRefWrapper accountId={account.id} inline>{children}</HoverRefWrapper>}
|
||||
|
|
|
@ -50,7 +50,7 @@ const AnimatedNumber: React.FC<IAnimatedNumber> = ({ value, obfuscate }) => {
|
|||
return (
|
||||
<TransitionMotion styles={styles} willEnter={willEnter} willLeave={willLeave}>
|
||||
{items => (
|
||||
<span className='inline-flex flex-col items-stretch relative overflow-hidden'>
|
||||
<span className='relative inline-flex flex-col items-stretch overflow-hidden'>
|
||||
{items.map(({ key, data, style }) => (
|
||||
<span key={key} style={{ position: (direction * style.y) > 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : <FormattedNumber value={data} />}</span>
|
||||
))}
|
||||
|
|
|
@ -24,7 +24,7 @@ const Emoji: React.FC<IEmoji> = ({ emoji, emojiMap, hovered }) => {
|
|||
return (
|
||||
<img
|
||||
draggable='false'
|
||||
className='emojione block m-0'
|
||||
className='emojione m-0 block'
|
||||
alt={emoji}
|
||||
title={title}
|
||||
src={joinPublicPath(`packs/emoji/${filename}.svg`)}
|
||||
|
@ -37,7 +37,7 @@ const Emoji: React.FC<IEmoji> = ({ emoji, emojiMap, hovered }) => {
|
|||
return (
|
||||
<img
|
||||
draggable='false'
|
||||
className='emojione block m-0'
|
||||
className='emojione m-0 block'
|
||||
alt={shortCode}
|
||||
title={shortCode}
|
||||
src={filename as string}
|
||||
|
|
|
@ -113,7 +113,7 @@ const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required })
|
|||
const handleChange = (date: Date) => onChange(date ? new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) : '');
|
||||
|
||||
return (
|
||||
<div className='mt-1 relative rounded-md shadow-sm'>
|
||||
<div className='relative mt-1 rounded-md shadow-sm'>
|
||||
<BundleContainer fetchComponent={DatePicker}>
|
||||
{Component => (<Component
|
||||
selected={selected}
|
||||
|
|
|
@ -196,7 +196,7 @@ class DropdownMenu extends React.PureComponent<IDropdownMenu, IDropdownMenuState
|
|||
data-method={isLogout ? 'delete' : undefined}
|
||||
title={text}
|
||||
>
|
||||
{icon && <SvgIcon src={icon} className='mr-3 rtl:ml-3 rtl:mr-0 h-5 w-5 flex-none' />}
|
||||
{icon && <SvgIcon src={icon} className='mr-3 h-5 w-5 flex-none rtl:ml-3 rtl:mr-0' />}
|
||||
|
||||
<span className='truncate'>{text}</span>
|
||||
|
||||
|
|
|
@ -113,17 +113,17 @@ class ErrorBoundary extends React.PureComponent<Props, State> {
|
|||
const errorText = this.getErrorText();
|
||||
|
||||
return (
|
||||
<div className='h-screen pt-16 pb-12 flex flex-col bg-white dark:bg-primary-900'>
|
||||
<main className='flex-grow flex flex-col justify-center max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8'>
|
||||
<div className='flex-shrink-0 flex justify-center'>
|
||||
<div className='flex h-screen flex-col bg-white pt-16 pb-12 dark:bg-primary-900'>
|
||||
<main className='mx-auto flex w-full max-w-7xl grow flex-col justify-center px-4 sm:px-6 lg:px-8'>
|
||||
<div className='flex shrink-0 justify-center'>
|
||||
<a href='/' className='inline-flex'>
|
||||
<SiteLogo alt='Logo' className='h-12 w-auto cursor-pointer' />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className='py-8'>
|
||||
<div className='text-center max-w-xl mx-auto space-y-2'>
|
||||
<h1 className='text-3xl font-extrabold text-gray-900 dark:text-gray-500 tracking-tight sm:text-4xl'>
|
||||
<div className='mx-auto max-w-xl space-y-2 text-center'>
|
||||
<h1 className='text-3xl font-extrabold tracking-tight text-gray-900 dark:text-gray-500 sm:text-4xl'>
|
||||
<FormattedMessage id='alert.unexpected.message' defaultMessage='Something went wrong.' />
|
||||
</h1>
|
||||
<p className='text-lg text-gray-700 dark:text-gray-600'>
|
||||
|
@ -132,7 +132,7 @@ class ErrorBoundary extends React.PureComponent<Props, State> {
|
|||
defaultMessage="We're sorry for the interruption. If the problem persists, please reach out to our support team. You may also try to {clearCookies} (this will log you out)."
|
||||
values={{
|
||||
clearCookies: (
|
||||
<a href='/' onClick={this.clearCookies} className='text-primary-600 dark:text-accent-blue hover:underline'>
|
||||
<a href='/' onClick={this.clearCookies} className='text-primary-600 hover:underline dark:text-accent-blue'>
|
||||
<FormattedMessage
|
||||
id='alert.unexpected.clear_cookies'
|
||||
defaultMessage='clear cookies and browser data'
|
||||
|
@ -150,7 +150,7 @@ class ErrorBoundary extends React.PureComponent<Props, State> {
|
|||
</Text>
|
||||
|
||||
<div className='mt-10'>
|
||||
<a href='/' className='text-base font-medium text-primary-600 dark:text-accent-blue hover:underline'>
|
||||
<a href='/' className='text-base font-medium text-primary-600 hover:underline dark:text-accent-blue'>
|
||||
<FormattedMessage id='alert.unexpected.return_home' defaultMessage='Return Home' />
|
||||
<span aria-hidden='true'> →</span>
|
||||
</a>
|
||||
|
@ -158,11 +158,11 @@ class ErrorBoundary extends React.PureComponent<Props, State> {
|
|||
</div>
|
||||
|
||||
{!isProduction && (
|
||||
<div className='py-16 max-w-lg mx-auto space-y-4'>
|
||||
<div className='mx-auto max-w-lg space-y-4 py-16'>
|
||||
{errorText && (
|
||||
<textarea
|
||||
ref={this.setTextareaRef}
|
||||
className='h-48 p-4 shadow-sm bg-gray-100 text-gray-900 dark:text-gray-100 dark:bg-gray-800 focus:ring-2 focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 dark:border-gray-700 rounded-md font-mono'
|
||||
className='block h-48 w-full rounded-md border-gray-300 bg-gray-100 p-4 font-mono text-gray-900 shadow-sm focus:border-primary-500 focus:ring-2 focus:ring-primary-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 sm:text-sm'
|
||||
value={errorText}
|
||||
onClick={this.handleCopy}
|
||||
readOnly
|
||||
|
@ -180,11 +180,11 @@ class ErrorBoundary extends React.PureComponent<Props, State> {
|
|||
</div>
|
||||
</main>
|
||||
|
||||
<footer className='flex-shrink-0 max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8'>
|
||||
<footer className='mx-auto w-full max-w-7xl shrink-0 px-4 sm:px-6 lg:px-8'>
|
||||
<HStack justifyContent='center' space={4} element='nav'>
|
||||
{links.get('status') && (
|
||||
<>
|
||||
<a href={links.get('status')} className='text-sm font-medium text-gray-700 dark:text-gray-600 hover:underline'>
|
||||
<a href={links.get('status')} className='text-sm font-medium text-gray-700 hover:underline dark:text-gray-600'>
|
||||
<FormattedMessage id='alert.unexpected.links.status' defaultMessage='Status' />
|
||||
</a>
|
||||
</>
|
||||
|
@ -193,7 +193,7 @@ class ErrorBoundary extends React.PureComponent<Props, State> {
|
|||
{links.get('help') && (
|
||||
<>
|
||||
<span className='inline-block border-l border-gray-300' aria-hidden='true' />
|
||||
<a href={links.get('help')} className='text-sm font-medium text-gray-700 dark:text-gray-600 hover:underline'>
|
||||
<a href={links.get('help')} className='text-sm font-medium text-gray-700 hover:underline dark:text-gray-600'>
|
||||
<FormattedMessage id='alert.unexpected.links.help' defaultMessage='Help Center' />
|
||||
</a>
|
||||
</>
|
||||
|
@ -202,7 +202,7 @@ class ErrorBoundary extends React.PureComponent<Props, State> {
|
|||
{links.get('support') && (
|
||||
<>
|
||||
<span className='inline-block border-l border-gray-300' aria-hidden='true' />
|
||||
<a href={links.get('support')} className='text-sm font-medium text-gray-700 dark:text-gray-600 hover:underline'>
|
||||
<a href={links.get('support')} className='text-sm font-medium text-gray-700 hover:underline dark:text-gray-600'>
|
||||
<FormattedMessage id='alert.unexpected.links.support' defaultMessage='Support' />
|
||||
</a>
|
||||
</>
|
||||
|
|
|
@ -55,7 +55,7 @@ const EventPreview: React.FC<IEventPreview> = ({ status, className, hideAction,
|
|||
<div className='absolute top-28 right-3'>
|
||||
{floatingAction && action}
|
||||
</div>
|
||||
<div className='bg-primary-200 dark:bg-gray-600 h-40'>
|
||||
<div className='h-40 bg-primary-200 dark:bg-gray-600'>
|
||||
{banner && <img className='h-full w-full object-cover' src={banner.url} alt={intl.formatMessage(messages.eventBanner)} />}
|
||||
</div>
|
||||
<Stack className='p-2.5' space={2}>
|
||||
|
@ -65,7 +65,7 @@ const EventPreview: React.FC<IEventPreview> = ({ status, className, hideAction,
|
|||
{!floatingAction && action}
|
||||
</HStack>
|
||||
|
||||
<div className='flex gap-y-1 gap-x-2 flex-wrap text-gray-700 dark:text-gray-600'>
|
||||
<div className='flex flex-wrap gap-y-1 gap-x-2 text-gray-700 dark:text-gray-600'>
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Icon src={require('@tabler/icons/user.svg')} />
|
||||
<HStack space={1} alignItems='center' grow>
|
||||
|
|
|
@ -31,7 +31,7 @@ const GdprBanner: React.FC = () => {
|
|||
|
||||
return (
|
||||
<Banner theme='opaque' className={classNames('transition-transform', { 'translate-y-full': slideout })}>
|
||||
<div className='flex flex-col space-y-4 lg:space-y-0 lg:space-x-4 rtl:space-x-reverse lg:flex-row lg:items-center lg:justify-between'>
|
||||
<div className='flex flex-col space-y-4 rtl:space-x-reverse lg:flex-row lg:items-center lg:justify-between lg:space-y-0 lg:space-x-4'>
|
||||
<Stack space={2}>
|
||||
<Text size='xl' weight='bold'>
|
||||
<FormattedMessage id='gdpr.title' defaultMessage='{siteTitle} uses cookies' values={{ siteTitle: instance.title }} />
|
||||
|
|
|
@ -18,9 +18,9 @@ const GroupCard: React.FC<IGroupCard> = ({ group }) => {
|
|||
|
||||
return (
|
||||
<div className='overflow-hidden'>
|
||||
<Stack className='bg-white dark:bg-primary-900 border border-solid border-gray-300 dark:border-primary-800 rounded-lg sm:rounded-xl'>
|
||||
<div className='bg-primary-100 dark:bg-gray-800 h-[120px] relative -m-[1px] mb-0 rounded-t-lg sm:rounded-t-xl'>
|
||||
{group.header && <img className='h-full w-full object-cover rounded-t-lg sm:rounded-t-xl' src={group.header} alt={intl.formatMessage(messages.groupHeader)} />}
|
||||
<Stack className='rounded-lg border border-solid border-gray-300 bg-white dark:border-primary-800 dark:bg-primary-900 sm:rounded-xl'>
|
||||
<div className='relative -m-[1px] mb-0 h-[120px] rounded-t-lg bg-primary-100 dark:bg-gray-800 sm:rounded-t-xl'>
|
||||
{group.header && <img className='h-full w-full rounded-t-lg object-cover sm:rounded-t-xl' src={group.header} alt={intl.formatMessage(messages.groupHeader)} />}
|
||||
<div className='absolute left-1/2 bottom-0 -translate-x-1/2 translate-y-1/2'>
|
||||
<Avatar className='ring-2 ring-white dark:ring-primary-900' src={group.avatar} size={64} />
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
|
||||
/** Fullscreen gradient used as a backdrop to public pages. */
|
||||
const LandingGradient: React.FC = () => (
|
||||
<div className='fixed h-screen w-full bg-gradient-to-tr from-primary-50 dark:from-primary-900/50 via-white dark:via-primary-900 to-gradient-end/10 dark:to-primary-800/50' />
|
||||
<div className='fixed h-screen w-full bg-gradient-to-tr from-primary-50 via-white to-gradient-end/10 dark:from-primary-900/50 dark:via-primary-900 dark:to-primary-800/50' />
|
||||
);
|
||||
|
||||
export default LandingGradient;
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Link as Comp, LinkProps } from 'react-router-dom';
|
|||
const Link = (props: LinkProps) => (
|
||||
<Comp
|
||||
{...props}
|
||||
className='text-primary-600 dark:text-accent-blue hover:underline'
|
||||
className='text-primary-600 hover:underline dark:text-accent-blue'
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ const LoadingScreen: React.FC = () => {
|
|||
<div className='fixed h-screen w-screen'>
|
||||
<LandingGradient />
|
||||
|
||||
<div className='fixed d-screen w-screen flex items-center justify-center z-10'>
|
||||
<div className='d-screen fixed z-10 flex w-screen items-center justify-center'>
|
||||
<div className='p-4'>
|
||||
<Spinner size={40} withText={false} />
|
||||
</div>
|
||||
|
|
|
@ -171,7 +171,7 @@ const Item: React.FC<IItem> = ({
|
|||
target='_blank'
|
||||
>
|
||||
<StillImage
|
||||
className='w-full h-full'
|
||||
className='h-full w-full'
|
||||
src={mediaPreview ? attachment.preview_url : attachment.url}
|
||||
alt={attachment.description}
|
||||
letterboxed={letterboxed}
|
||||
|
|
|
@ -241,7 +241,7 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
|
|||
<div
|
||||
role='presentation'
|
||||
id='modal-overlay'
|
||||
className='fixed inset-0 bg-gray-500/90 dark:bg-gray-700/90 backdrop-blur'
|
||||
className='fixed inset-0 bg-gray-500/90 backdrop-blur dark:bg-gray-700/90'
|
||||
onClick={handleOnClose}
|
||||
/>
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ const PollPercentageBar: React.FC<{ percent: number, leading: boolean }> = ({ pe
|
|||
<Motion defaultStyle={{ width: 0 }} style={{ width: spring(percent, { ...presets.gentle, precision: 0.1 }) }}>
|
||||
{({ width }) => (
|
||||
<span
|
||||
className='absolute inset-0 h-full inline-block bg-primary-100 dark:bg-primary-500 rounded-l-md'
|
||||
className='absolute inset-0 inline-block h-full rounded-l-md bg-primary-100 dark:bg-primary-500'
|
||||
style={{ width: `${width}%` }}
|
||||
/>
|
||||
)}
|
||||
|
@ -61,8 +61,8 @@ const PollOptionText: React.FC<IPollOptionText> = ({ poll, option, index, active
|
|||
onChange={handleOptionChange}
|
||||
/>
|
||||
|
||||
<div className='grid items-center w-full'>
|
||||
<div className='col-start-1 row-start-1 justify-self-center ml-4 mr-6'>
|
||||
<div className='grid w-full items-center'>
|
||||
<div className='col-start-1 row-start-1 ml-4 mr-6 justify-self-center'>
|
||||
<div className='text-primary-600 dark:text-white'>
|
||||
<Text
|
||||
theme='inherit'
|
||||
|
@ -72,7 +72,7 @@ const PollOptionText: React.FC<IPollOptionText> = ({ poll, option, index, active
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className='col-start-1 row-start-1 justify-self-end flex items-center'>
|
||||
<div className='col-start-1 row-start-1 flex items-center justify-self-end'>
|
||||
<span
|
||||
className={classNames('flex items-center justify-center w-6 h-6 flex-none border border-solid rounded-full', {
|
||||
'bg-primary-600 border-primary-600 dark:bg-primary-300 dark:border-primary-300': active,
|
||||
|
@ -85,7 +85,7 @@ const PollOptionText: React.FC<IPollOptionText> = ({ poll, option, index, active
|
|||
aria-label={option.title}
|
||||
>
|
||||
{active && (
|
||||
<Icon src={require('@tabler/icons/check.svg')} className='text-white dark:text-primary-900 w-4 h-4' />
|
||||
<Icon src={require('@tabler/icons/check.svg')} className='h-4 w-4 text-white dark:text-primary-900' />
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
@ -123,7 +123,7 @@ const PollOption: React.FC<IPollOption> = (props): JSX.Element | null => {
|
|||
<HStack
|
||||
justifyContent='between'
|
||||
alignItems='center'
|
||||
className='relative p-2 w-full bg-white dark:bg-primary-800 rounded-md overflow-hidden'
|
||||
className='relative w-full overflow-hidden rounded-md bg-white p-2 dark:bg-primary-800'
|
||||
>
|
||||
<PollPercentageBar percent={percent} leading={leading} />
|
||||
|
||||
|
@ -141,7 +141,7 @@ const PollOption: React.FC<IPollOption> = (props): JSX.Element | null => {
|
|||
<Icon
|
||||
src={require('@tabler/icons/circle-check.svg')}
|
||||
alt={intl.formatMessage(messages.voted)}
|
||||
className='text-primary-600 dark:text-primary-800 dark:fill-white w-4 h-4'
|
||||
className='h-4 w-4 text-primary-600 dark:fill-white dark:text-primary-800'
|
||||
/>
|
||||
) : (
|
||||
<div className='svg-icon' />
|
||||
|
|
|
@ -123,7 +123,7 @@ export const ProfileHoverCard: React.FC<IProfileHoverCard> = ({ visible = true }
|
|||
<HStack alignItems='center' space={0.5}>
|
||||
<Icon
|
||||
src={require('@tabler/icons/calendar.svg')}
|
||||
className='w-4 h-4 text-gray-800 dark:text-gray-200'
|
||||
className='h-4 w-4 text-gray-800 dark:text-gray-200'
|
||||
/>
|
||||
|
||||
<Text size='sm'>
|
||||
|
|
|
@ -83,7 +83,7 @@ const ScrollTopButton: React.FC<IScrollTopButton> = ({
|
|||
|
||||
return (
|
||||
<div className={classes}>
|
||||
<a className='flex items-center bg-primary-600 hover:bg-primary-700 hover:scale-105 active:scale-100 transition-transform text-white rounded-full px-4 py-2 space-x-1.5 cursor-pointer whitespace-nowrap' onClick={handleClick}>
|
||||
<a className='flex cursor-pointer items-center space-x-1.5 whitespace-nowrap rounded-full bg-primary-600 px-4 py-2 text-white transition-transform hover:scale-105 hover:bg-primary-700 active:scale-100' onClick={handleClick}>
|
||||
<Icon src={require('@tabler/icons/arrow-bar-to-up.svg')} />
|
||||
|
||||
{(count > 0) && (
|
||||
|
|
|
@ -53,8 +53,8 @@ interface ISidebarLink {
|
|||
const SidebarLink: React.FC<ISidebarLink> = ({ href, to, icon, text, onClick }) => {
|
||||
const body = (
|
||||
<HStack space={2} alignItems='center'>
|
||||
<div className='bg-primary-50 dark:bg-gray-800 relative rounded-full inline-flex p-2'>
|
||||
<Icon src={icon} className='text-primary-500 h-5 w-5' />
|
||||
<div className='relative inline-flex rounded-full bg-primary-50 p-2 dark:bg-gray-800'>
|
||||
<Icon src={icon} className='h-5 w-5 text-primary-500' />
|
||||
</div>
|
||||
|
||||
<Text tag='span' weight='medium' theme='inherit'>{text}</Text>
|
||||
|
@ -63,14 +63,14 @@ const SidebarLink: React.FC<ISidebarLink> = ({ href, to, icon, text, onClick })
|
|||
|
||||
if (to) {
|
||||
return (
|
||||
<NavLink className='group rounded-full text-gray-900 dark:text-gray-100 hover:bg-gray-50 dark:hover:bg-gray-800' to={to} onClick={onClick}>
|
||||
<NavLink className='group rounded-full text-gray-900 hover:bg-gray-50 dark:text-gray-100 dark:hover:bg-gray-800' to={to} onClick={onClick}>
|
||||
{body}
|
||||
</NavLink>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<a className='group rounded-full text-gray-900 dark:text-gray-100 hover:bg-gray-50 dark:hover:bg-gray-800' href={href} target='_blank' onClick={onClick}>
|
||||
<a className='group rounded-full text-gray-900 hover:bg-gray-50 dark:text-gray-100 dark:hover:bg-gray-800' href={href} target='_blank' onClick={onClick}>
|
||||
{body}
|
||||
</a>
|
||||
);
|
||||
|
@ -165,10 +165,10 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
src={require('@tabler/icons/x.svg')}
|
||||
ref={closeButtonRef}
|
||||
iconClassName='h-6 w-6'
|
||||
className='absolute top-0 right-0 -mr-11 mt-2 text-gray-600 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300'
|
||||
className='absolute top-0 right-0 -mr-11 mt-2 text-gray-600 hover:text-gray-600 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
/>
|
||||
|
||||
<div className='relative overflow-y-scroll overflow-auto h-full w-full'>
|
||||
<div className='relative h-full w-full overflow-auto overflow-y-scroll'>
|
||||
<div className='p-4'>
|
||||
<Stack space={4}>
|
||||
<Link to={`/@${account.acct}`} onClick={onClose}>
|
||||
|
@ -342,11 +342,11 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
</button>
|
||||
|
||||
{switcher && (
|
||||
<div className='border-t-2 border-gray-100 dark:border-gray-800 border-solid'>
|
||||
<div className='border-t-2 border-solid border-gray-100 dark:border-gray-800'>
|
||||
{otherAccounts.map(account => renderAccount(account))}
|
||||
|
||||
<NavLink className='flex items-center py-2 space-x-1' to='/login/add' onClick={handleClose}>
|
||||
<Icon className='text-primary-500 w-4 h-4' src={require('@tabler/icons/plus.svg')} />
|
||||
<NavLink className='flex items-center space-x-1 py-2' to='/login/add' onClick={handleClose}>
|
||||
<Icon className='h-4 w-4 text-primary-500' src={require('@tabler/icons/plus.svg')} />
|
||||
<Text size='sm' weight='medium'>{intl.formatMessage(messages.addAccount)}</Text>
|
||||
</NavLink>
|
||||
</div>
|
||||
|
@ -361,7 +361,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
{/* Dummy element to keep Close Icon visible */}
|
||||
<div
|
||||
aria-hidden
|
||||
className='w-14 flex-shrink-0'
|
||||
className='w-14 shrink-0'
|
||||
onClick={handleClose}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -41,8 +41,8 @@ const StatusActionButton = React.forwardRef<HTMLButtonElement, IStatusActionButt
|
|||
const renderIcon = () => {
|
||||
if (emoji) {
|
||||
return (
|
||||
<span className='flex w-6 h-6 items-center justify-center'>
|
||||
<Emoji className='w-full h-full p-0.5' emoji={emoji} />
|
||||
<span className='flex h-6 w-6 items-center justify-center'>
|
||||
<Emoji className='h-full w-full p-0.5' emoji={emoji} />
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -25,7 +25,7 @@ interface IReadMoreButton {
|
|||
|
||||
/** Button to expand a truncated status (due to too much content) */
|
||||
const ReadMoreButton: React.FC<IReadMoreButton> = ({ onClick }) => (
|
||||
<button className='flex items-center text-gray-900 dark:text-gray-300 border-0 bg-transparent p-0 pt-2 hover:underline active:underline' onClick={onClick}>
|
||||
<button className='flex items-center border-0 bg-transparent p-0 pt-2 text-gray-900 hover:underline active:underline dark:text-gray-300' onClick={onClick}>
|
||||
<FormattedMessage id='status.read_more' defaultMessage='Read more' />
|
||||
<Icon className='inline-block h-5 w-5' src={require('@tabler/icons/chevron-right.svg')} />
|
||||
</button>
|
||||
|
|
|
@ -73,7 +73,7 @@ const StatusReplyMentions: React.FC<IStatusReplyMentions> = ({ status, hoverable
|
|||
|
||||
if (to.size > 2) {
|
||||
accounts.push(
|
||||
<span key='more' className='hover:underline cursor-pointer' role='button' onClick={handleOpenMentionsModal} tabIndex={0}>
|
||||
<span key='more' className='cursor-pointer hover:underline' role='button' onClick={handleOpenMentionsModal} tabIndex={0}>
|
||||
<FormattedMessage id='reply_mentions.more' defaultMessage='{count} more' values={{ count: to.size - 2 }} />
|
||||
</span>,
|
||||
);
|
||||
|
@ -93,7 +93,7 @@ const StatusReplyMentions: React.FC<IStatusReplyMentions> = ({ status, hoverable
|
|||
<HoverStatusWrapper statusId={status.in_reply_to_id} inline>
|
||||
<span
|
||||
key='hoverstatus'
|
||||
className='hover:underline cursor-pointer'
|
||||
className='cursor-pointer hover:underline'
|
||||
role='presentation'
|
||||
>
|
||||
{children}
|
||||
|
|
|
@ -107,8 +107,8 @@ const SensitiveContentOverlay = React.forwardRef<HTMLDivElement, ISensitiveConte
|
|||
size='sm'
|
||||
/>
|
||||
) : (
|
||||
<div className='flex justify-center items-center max-h-screen'>
|
||||
<div className='text-center w-3/4 mx-auto space-y-4' ref={ref}>
|
||||
<div className='flex max-h-screen items-center justify-center'>
|
||||
<div className='mx-auto w-3/4 space-y-4 text-center' ref={ref}>
|
||||
<div className='space-y-1'>
|
||||
<Text theme='white' weight='semibold'>
|
||||
{intl.formatMessage(isUnderReview ? messages.underReviewTitle : messages.sensitiveTitle)}
|
||||
|
|
|
@ -21,7 +21,7 @@ const StatusInfo = (props: IStatusInfo) => {
|
|||
return (
|
||||
<Container
|
||||
{...containerProps}
|
||||
className='flex items-center text-gray-700 dark:text-gray-600 text-xs font-medium space-x-3 rtl:space-x-reverse hover:underline'
|
||||
className='flex items-center space-x-3 text-xs font-medium text-gray-700 hover:underline rtl:space-x-reverse dark:text-gray-600'
|
||||
>
|
||||
<div
|
||||
className='flex justify-end'
|
||||
|
|
|
@ -70,7 +70,7 @@ const StillImage: React.FC<IStillImage> = ({ alt, className, src, style, letterb
|
|||
)}
|
||||
|
||||
{(hoverToPlay && showExt) && (
|
||||
<div className='group-hover:hidden absolute opacity-90 left-2 bottom-2 pointer-events-none'>
|
||||
<div className='pointer-events-none absolute left-2 bottom-2 opacity-90 group-hover:hidden'>
|
||||
<ExtensionBadge ext='GIF' />
|
||||
</div>
|
||||
)}
|
||||
|
@ -86,7 +86,7 @@ interface IExtensionBadge {
|
|||
/** Badge displaying a file extension. */
|
||||
const ExtensionBadge: React.FC<IExtensionBadge> = ({ ext }) => {
|
||||
return (
|
||||
<div className='inline-flex items-center px-2 py-0.5 rounded text-sm font-medium bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100'>
|
||||
<div className='inline-flex items-center rounded bg-gray-100 px-2 py-0.5 text-sm font-medium text-gray-900 dark:bg-gray-800 dark:text-gray-100'>
|
||||
{ext}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -19,7 +19,7 @@ const Tombstone: React.FC<ITombstone> = ({ id, onMoveUp, onMoveDown }) => {
|
|||
|
||||
return (
|
||||
<HotKeys handlers={handlers}>
|
||||
<div className='p-9 flex items-center justify-center sm:rounded-xl bg-gray-100 border border-solid border-gray-200 dark:bg-gray-900 dark:border-gray-800 focusable' tabIndex={0}>
|
||||
<div className='focusable flex items-center justify-center border border-solid border-gray-200 bg-gray-100 p-9 dark:border-gray-800 dark:bg-gray-900 sm:rounded-xl' tabIndex={0}>
|
||||
<Text>
|
||||
<FormattedMessage id='statuses.tombstone' defaultMessage='One or more posts are unavailable.' />
|
||||
</Text>
|
||||
|
|
|
@ -36,13 +36,13 @@ const Accordion: React.FC<IAccordion> = ({ headline, children, menu, expanded =
|
|||
};
|
||||
|
||||
return (
|
||||
<div className='bg-white dark:bg-primary-800 text-gray-900 dark:text-gray-100 rounded-lg shadow dark:shadow-none'>
|
||||
<div className='rounded-lg bg-white text-gray-900 shadow dark:bg-primary-800 dark:text-gray-100 dark:shadow-none'>
|
||||
<button
|
||||
type='button'
|
||||
onClick={handleToggle}
|
||||
title={intl.formatMessage(expanded ? messages.collapse : messages.expand)}
|
||||
aria-expanded={expanded}
|
||||
className='px-4 py-3 font-semibold flex items-center justify-between w-full'
|
||||
className='flex w-full items-center justify-between px-4 py-3 font-semibold'
|
||||
>
|
||||
<span>{headline}</span>
|
||||
|
||||
|
@ -55,7 +55,7 @@ const Accordion: React.FC<IAccordion> = ({ headline, children, menu, expanded =
|
|||
)}
|
||||
<Icon
|
||||
src={expanded ? require('@tabler/icons/chevron-up.svg') : require('@tabler/icons/chevron-down.svg')}
|
||||
className='text-gray-700 dark:text-gray-600 h-5 w-5'
|
||||
className='h-5 w-5 text-gray-700 dark:text-gray-600'
|
||||
/>
|
||||
</HStack>
|
||||
</button>
|
||||
|
|
|
@ -17,7 +17,7 @@ const Banner: React.FC<IBanner> = ({ theme, children, className }) => {
|
|||
'bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-3xl dark:shadow-inset': theme === 'opaque',
|
||||
}, className)}
|
||||
>
|
||||
<div className='max-w-4xl mx-auto px-4'>
|
||||
<div className='mx-auto max-w-4xl px-4'>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -63,7 +63,7 @@ const Button = React.forwardRef<HTMLButtonElement, IButton>((props, ref): JSX.El
|
|||
return null;
|
||||
}
|
||||
|
||||
return <Icon src={icon} className='w-4 h-4' />;
|
||||
return <Icon src={icon} className='h-4 w-4' />;
|
||||
};
|
||||
|
||||
const handleClick: React.MouseEventHandler<HTMLButtonElement> = React.useCallback((event) => {
|
||||
|
|
|
@ -64,7 +64,7 @@ const CardHeader: React.FC<ICardHeader> = ({ className, children, backHref, onBa
|
|||
const backAttributes = backHref ? { to: backHref } : { onClick: onBackClick };
|
||||
|
||||
return (
|
||||
<Comp {...backAttributes} className='text-gray-900 dark:text-gray-100 focus:ring-primary-500 focus:ring-2' aria-label={intl.formatMessage(messages.back)}>
|
||||
<Comp {...backAttributes} className='text-gray-900 focus:ring-2 focus:ring-primary-500 dark:text-gray-100' aria-label={intl.formatMessage(messages.back)}>
|
||||
<SvgIcon src={require('@tabler/icons/arrow-left.svg')} className='h-6 w-6 rtl:rotate-180' />
|
||||
<span className='sr-only' data-testid='back-button'>{intl.formatMessage(messages.back)}</span>
|
||||
</Comp>
|
||||
|
|
|
@ -9,7 +9,7 @@ const Checkbox = React.forwardRef<HTMLInputElement, ICheckbox>((props, ref) => {
|
|||
{...props}
|
||||
ref={ref}
|
||||
type='checkbox'
|
||||
className='border-2 dark:bg-gray-900 dark:border-gray-800 focus:ring-primary-500 h-4 w-4 text-primary-600 border-gray-300 rounded'
|
||||
className='h-4 w-4 rounded border-2 border-gray-300 text-primary-600 focus:ring-primary-500 dark:border-gray-800 dark:bg-gray-900'
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@ interface ICounter {
|
|||
/** A simple counter for notifications, etc. */
|
||||
const Counter: React.FC<ICounter> = ({ count, countMax }) => {
|
||||
return (
|
||||
<span className='h-5 min-w-[20px] max-w-[26px] flex items-center justify-center bg-secondary-500 text-xs font-medium text-white rounded-full ring-2 ring-white dark:ring-gray-800'>
|
||||
<span className='flex h-5 min-w-[20px] max-w-[26px] items-center justify-center rounded-full bg-secondary-500 text-xs font-medium text-white ring-2 ring-white dark:ring-gray-800'>
|
||||
{shortNumberFormat(count, countMax)}
|
||||
</span>
|
||||
);
|
||||
|
|
|
@ -31,7 +31,7 @@ const Datepicker = ({ onChange }: IDatepicker) => {
|
|||
}, [month, day, year]);
|
||||
|
||||
return (
|
||||
<div className='grid grid-cols-1 gap-y-2 gap-x-2 sm:grid-cols-3'>
|
||||
<div className='grid grid-cols-1 gap-2 sm:grid-cols-3'>
|
||||
<div className='sm:col-span-1'>
|
||||
<Stack>
|
||||
<Text size='sm' weight='medium' theme='muted'>
|
||||
|
|
|
@ -13,12 +13,12 @@ interface IDivider {
|
|||
const Divider = ({ text, textSize = 'md' }: IDivider) => (
|
||||
<div className='relative' data-testid='divider'>
|
||||
<div className='absolute inset-0 flex items-center' aria-hidden='true'>
|
||||
<div className='w-full border-t-2 border-gray-100 dark:border-gray-800 border-solid' />
|
||||
<div className='w-full border-t-2 border-solid border-gray-100 dark:border-gray-800' />
|
||||
</div>
|
||||
|
||||
{text && (
|
||||
<div className='relative flex justify-center'>
|
||||
<span className='px-2 bg-white dark:bg-gray-900 text-gray-700 dark:text-gray-600' data-testid='divider-text'>
|
||||
<span className='bg-white px-2 text-gray-700 dark:bg-gray-900 dark:text-gray-600' data-testid='divider-text'>
|
||||
<Text size={textSize} tag='span' theme='inherit'>{text}</Text>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -18,7 +18,7 @@ interface IEmojiButton {
|
|||
const EmojiButton: React.FC<IEmojiButton> = ({ emoji, className, onClick, tabIndex }): JSX.Element => {
|
||||
return (
|
||||
<button className={classNames(className)} onClick={onClick} tabIndex={tabIndex}>
|
||||
<Emoji className='w-8 h-8 duration-100 hover:scale-125' emoji={emoji} />
|
||||
<Emoji className='h-8 w-8 duration-100 hover:scale-125' emoji={emoji} />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ const FileInput = forwardRef<HTMLInputElement, IFileInput>((props, ref) => {
|
|||
{...props}
|
||||
ref={ref}
|
||||
type='file'
|
||||
className='block w-full text-sm text-gray-800 dark:text-gray-200 file:cursor-pointer file:mr-2 file:py-1.5 file:px-3 file:rounded-full file:text-xs file:leading-4 file:font-medium file:border-gray-200 file:border file:border-solid file:bg-white file:text-gray-700 hover:file:bg-gray-100 dark:file:border-gray-800 dark:file:bg-gray-900 dark:file:hover:bg-gray-800 dark:file:text-gray-500'
|
||||
className='block w-full text-sm text-gray-800 file:mr-2 file:cursor-pointer file:rounded-full file:border file:border-solid file:border-gray-200 file:bg-white file:py-1.5 file:px-3 file:text-xs file:font-medium file:leading-4 file:text-gray-700 hover:file:bg-gray-100 dark:text-gray-200 dark:file:border-gray-800 dark:file:bg-gray-900 dark:file:text-gray-500 dark:file:hover:bg-gray-800'
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -55,7 +55,7 @@ const FormGroup: React.FC<IFormGroup> = (props) => {
|
|||
<div>
|
||||
<p
|
||||
data-testid='form-group-error'
|
||||
className='mt-0.5 text-xs text-danger-900 bg-danger-200 rounded-md inline-block px-2 py-1 relative form-error'
|
||||
className='form-error relative mt-0.5 inline-block rounded-md bg-danger-200 px-2 py-1 text-xs text-danger-900'
|
||||
>
|
||||
{errors.join(', ')}
|
||||
</p>
|
||||
|
@ -92,7 +92,7 @@ const FormGroup: React.FC<IFormGroup> = (props) => {
|
|||
{hasError && (
|
||||
<p
|
||||
data-testid='form-group-error'
|
||||
className='mt-0.5 text-xs text-danger-900 bg-danger-200 rounded-md inline-block px-2 py-1 relative form-error'
|
||||
className='form-error relative mt-0.5 inline-block rounded-md bg-danger-200 px-2 py-1 text-xs text-danger-900'
|
||||
>
|
||||
{errors.join(', ')}
|
||||
</p>
|
||||
|
|
|
@ -21,9 +21,9 @@ interface IIcon extends Pick<React.SVGAttributes<SVGAElement>, 'strokeWidth'> {
|
|||
|
||||
/** Renders and SVG icon with optional counter. */
|
||||
const Icon: React.FC<IIcon> = ({ src, alt, count, size, countMax, ...filteredProps }): JSX.Element => (
|
||||
<div className='flex flex-col flex-shrink-0 relative' data-testid='icon'>
|
||||
<div className='relative flex shrink-0 flex-col' data-testid='icon'>
|
||||
{count ? (
|
||||
<span className='absolute -top-2 -right-3 min-w-[20px] h-5 flex-shrink-0 whitespace-nowrap flex items-center justify-center break-words'>
|
||||
<span className='absolute -top-2 -right-3 flex h-5 min-w-[20px] shrink-0 items-center justify-center whitespace-nowrap break-words'>
|
||||
<Counter count={count} countMax={countMax} />
|
||||
</span>
|
||||
) : null}
|
||||
|
|
|
@ -68,7 +68,7 @@ const Input = React.forwardRef<HTMLInputElement, IInput>(
|
|||
}
|
||||
>
|
||||
{icon ? (
|
||||
<div className='absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none'>
|
||||
<div className='pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3'>
|
||||
<Icon src={icon} className='h-4 w-4 text-gray-700 dark:text-gray-600' aria-hidden='true' />
|
||||
</div>
|
||||
) : null}
|
||||
|
@ -95,7 +95,7 @@ const Input = React.forwardRef<HTMLInputElement, IInput>(
|
|||
/>
|
||||
|
||||
{append ? (
|
||||
<div className='absolute inset-y-0 right-0 rtl:left-0 rtl:right-auto flex items-center pr-3'>
|
||||
<div className='absolute inset-y-0 right-0 flex items-center pr-3 rtl:left-0 rtl:right-auto'>
|
||||
{append}
|
||||
</div>
|
||||
) : null}
|
||||
|
@ -108,12 +108,12 @@ const Input = React.forwardRef<HTMLInputElement, IInput>(
|
|||
intl.formatMessage(messages.showPassword)
|
||||
}
|
||||
>
|
||||
<div className='absolute inset-y-0 right-0 rtl:left-0 rtl:right-auto flex items-center'>
|
||||
<div className='absolute inset-y-0 right-0 flex items-center rtl:left-0 rtl:right-auto'>
|
||||
<button
|
||||
type='button'
|
||||
onClick={togglePassword}
|
||||
tabIndex={-1}
|
||||
className='text-gray-700 dark:text-gray-600 hover:text-gray-500 dark:hover:text-gray-400 h-full px-2 focus:ring-primary-500 focus:ring-2'
|
||||
className='h-full px-2 text-gray-700 hover:text-gray-500 focus:ring-2 focus:ring-primary-500 dark:text-gray-600 dark:hover:text-gray-400'
|
||||
>
|
||||
<SvgIcon
|
||||
src={revealed ? require('@tabler/icons/eye-off.svg') : require('@tabler/icons/eye.svg')}
|
||||
|
|
|
@ -21,8 +21,8 @@ interface LayoutComponent extends React.FC<ILayout> {
|
|||
|
||||
/** Layout container, to hold Sidebar, Main, and Aside. */
|
||||
const Layout: LayoutComponent = ({ children }) => (
|
||||
<div className='sm:pt-4 relative'>
|
||||
<div className='max-w-3xl mx-auto sm:px-6 md:max-w-7xl md:px-8 md:grid md:grid-cols-12 md:gap-8'>
|
||||
<div className='relative sm:pt-4'>
|
||||
<div className='mx-auto max-w-3xl sm:px-6 md:grid md:max-w-7xl md:grid-cols-12 md:gap-8 md:px-8'>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -30,7 +30,7 @@ const Layout: LayoutComponent = ({ children }) => (
|
|||
|
||||
/** Left sidebar container in the UI. */
|
||||
const Sidebar: React.FC<ISidebar> = ({ children }) => (
|
||||
<div className='hidden lg:block lg:col-span-3'>
|
||||
<div className='hidden lg:col-span-3 lg:block'>
|
||||
<StickyBox offsetTop={80} className='pb-4'>
|
||||
{children}
|
||||
</StickyBox>
|
||||
|
@ -50,7 +50,7 @@ const Main: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ children, classN
|
|||
|
||||
/** Right sidebar container in the UI. */
|
||||
const Aside: React.FC<IAside> = ({ children }) => (
|
||||
<aside className='hidden xl:block xl:col-span-3'>
|
||||
<aside className='hidden xl:col-span-3 xl:block'>
|
||||
<StickyBox offsetTop={80} className='space-y-6 pb-12'>
|
||||
{children}
|
||||
</StickyBox>
|
||||
|
|
|
@ -88,7 +88,7 @@ const Modal: React.FC<IModal> = ({
|
|||
|
||||
return (
|
||||
<div data-testid='modal' className={classNames('block w-full p-6 mx-auto text-start align-middle transition-all transform bg-white dark:bg-primary-900 text-gray-900 dark:text-gray-100 shadow-xl rounded-2xl pointer-events-auto', widths[width])}>
|
||||
<div className='sm:flex sm:items-start w-full justify-between'>
|
||||
<div className='w-full justify-between sm:flex sm:items-start'>
|
||||
<div className='w-full'>
|
||||
{title && (
|
||||
<div
|
||||
|
@ -96,7 +96,7 @@ const Modal: React.FC<IModal> = ({
|
|||
'flex-row-reverse': closePosition === 'left',
|
||||
})}
|
||||
>
|
||||
<h3 className='flex-grow text-lg leading-6 font-bold text-gray-900 dark:text-white'>
|
||||
<h3 className='grow text-lg font-bold leading-6 text-gray-900 dark:text-white'>
|
||||
{title}
|
||||
</h3>
|
||||
|
||||
|
@ -105,14 +105,14 @@ const Modal: React.FC<IModal> = ({
|
|||
src={closeIcon}
|
||||
title={intl.formatMessage(messages.close)}
|
||||
onClick={onClose}
|
||||
className='text-gray-500 hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200 rtl:rotate-180'
|
||||
className='text-gray-500 hover:text-gray-700 rtl:rotate-180 dark:text-gray-300 dark:hover:text-gray-200'
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{title ? (
|
||||
<div className='w-full mt-2'>
|
||||
<div className='mt-2 w-full'>
|
||||
{children}
|
||||
</div>
|
||||
) : children}
|
||||
|
|
|
@ -12,7 +12,7 @@ const CountryCodeDropdown: React.FC<ICountryCodeDropdown> = ({ countryCode, onCh
|
|||
return (
|
||||
<select
|
||||
value={countryCode}
|
||||
className='h-full py-0 pl-3 pr-7 text-base bg-transparent border-transparent focus:outline-none focus:ring-primary-500 dark:text-white sm:text-sm rounded-md'
|
||||
className='h-full rounded-md border-transparent bg-transparent py-0 pl-3 pr-7 text-base focus:outline-none focus:ring-primary-500 dark:text-white sm:text-sm'
|
||||
onChange={(event) => onChange(event.target.value as any)}
|
||||
>
|
||||
{COUNTRY_CODES.map((code) => (
|
||||
|
|
|
@ -14,7 +14,7 @@ interface IProgressBar {
|
|||
/** A horizontal meter filled to the given percentage. */
|
||||
const ProgressBar: React.FC<IProgressBar> = ({ progress, size = 'md' }) => (
|
||||
<div
|
||||
className={clsx('h-2.5 w-full rounded-lg bg-gray-300 dark:bg-primary-800 overflow-hidden', {
|
||||
className={clsx('h-2.5 w-full overflow-hidden rounded-lg bg-gray-300 dark:bg-primary-800', {
|
||||
'h-2.5': size === 'md',
|
||||
'h-[6px]': size === 'sm',
|
||||
})}
|
||||
|
|
|
@ -11,7 +11,7 @@ const Select = React.forwardRef<HTMLSelectElement, ISelect>((props, ref) => {
|
|||
return (
|
||||
<select
|
||||
ref={ref}
|
||||
className={`w-full pl-3 pr-10 py-2 text-base truncate border-gray-300 dark:border-gray-800 focus:outline-none focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-900 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:focus:ring-primary-500 dark:focus:border-primary-500 sm:text-sm rounded-md disabled:opacity-50 ${className}`}
|
||||
className={`w-full truncate rounded-md border-gray-300 py-2 pl-3 pr-10 text-base focus:border-primary-500 focus:outline-none focus:ring-primary-500 disabled:opacity-50 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:focus:border-primary-500 dark:focus:ring-primary-500 sm:text-sm ${className}`}
|
||||
{...filteredProps}
|
||||
>
|
||||
{children}
|
||||
|
|
|
@ -53,14 +53,14 @@ const Slider: React.FC<ISlider> = ({ value, onChange }) => {
|
|||
|
||||
return (
|
||||
<div
|
||||
className='inline-flex cursor-pointer h-6 relative transition'
|
||||
className='relative inline-flex h-6 cursor-pointer transition'
|
||||
onMouseDown={handleMouseDown}
|
||||
ref={node}
|
||||
>
|
||||
<div className='w-full h-1 bg-primary-200 dark:bg-primary-700 absolute top-1/2 -translate-y-1/2 rounded-full' />
|
||||
<div className='h-1 bg-accent-500 absolute top-1/2 -translate-y-1/2 rounded-full' style={{ width: `${value * 100}%` }} />
|
||||
<div className='absolute top-1/2 h-1 w-full -translate-y-1/2 rounded-full bg-primary-200 dark:bg-primary-700' />
|
||||
<div className='absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-accent-500' style={{ width: `${value * 100}%` }} />
|
||||
<span
|
||||
className='bg-accent-500 absolute rounded-full w-3 h-3 -ml-1.5 top-1/2 -translate-y-1/2 z-10 shadow'
|
||||
className='absolute top-1/2 z-10 -ml-1.5 h-3 w-3 -translate-y-1/2 rounded-full bg-accent-500 shadow'
|
||||
tabIndex={0}
|
||||
style={{ left: `${value * 100}%` }}
|
||||
/>
|
||||
|
|
|
@ -46,7 +46,7 @@ const AnimatedTabs: React.FC<IAnimatedInterface> = ({ children, ...rest }) => {
|
|||
ref={ref}
|
||||
>
|
||||
<div
|
||||
className='w-full h-[3px] bg-primary-200 dark:bg-primary-700 absolute'
|
||||
className='absolute h-[3px] w-full bg-primary-200 dark:bg-primary-700'
|
||||
style={{ top }}
|
||||
/>
|
||||
<div
|
||||
|
|
|
@ -43,9 +43,9 @@ const TagInput: React.FC<ITagInput> = ({ tags, onChange, placeholder }) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className='mt-1 relative shadow-sm flex-grow'>
|
||||
<div className='relative mt-1 grow shadow-sm'>
|
||||
<HStack
|
||||
className='p-2 pb-0 text-gray-900 dark:text-gray-100 placeholder:text-gray-600 dark:placeholder:text-gray-600 block w-full sm:text-sm dark:ring-1 dark:ring-gray-800 focus:ring-primary-500 focus:border-primary-500 dark:focus:ring-primary-500 dark:focus:border-primary-500 rounded-md bg-white dark:bg-gray-900 border-gray-400 dark:border-gray-800'
|
||||
className='block w-full rounded-md border-gray-400 bg-white p-2 pb-0 text-gray-900 placeholder:text-gray-600 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus:border-primary-500 dark:focus:ring-primary-500 sm:text-sm'
|
||||
space={2}
|
||||
wrap
|
||||
>
|
||||
|
@ -56,7 +56,7 @@ const TagInput: React.FC<ITagInput> = ({ tags, onChange, placeholder }) => {
|
|||
))}
|
||||
|
||||
<input
|
||||
className='p-1 mb-2 w-32 h-8 flex-grow bg-transparent outline-none'
|
||||
className='mb-2 h-8 w-32 grow bg-transparent p-1 outline-none'
|
||||
value={input}
|
||||
placeholder={placeholder}
|
||||
onChange={e => setInput(e.target.value)}
|
||||
|
|
|
@ -13,7 +13,7 @@ interface ITag {
|
|||
/** A single editable Tag (used by TagInput). */
|
||||
const Tag: React.FC<ITag> = ({ tag, onDelete }) => {
|
||||
return (
|
||||
<div className='inline-flex p-1 rounded bg-primary-500 items-center whitespace-nowrap'>
|
||||
<div className='inline-flex items-center whitespace-nowrap rounded bg-primary-500 p-1'>
|
||||
<Text theme='white'>{tag}</Text>
|
||||
|
||||
<IconButton
|
||||
|
|
|
@ -40,7 +40,7 @@ const Toast = (props: IToast) => {
|
|||
return (
|
||||
<Icon
|
||||
src={require('@tabler/icons/circle-check.svg')}
|
||||
className='w-6 h-6 text-success-500 dark:text-success-400'
|
||||
className='h-6 w-6 text-success-500 dark:text-success-400'
|
||||
aria-hidden
|
||||
/>
|
||||
);
|
||||
|
@ -48,7 +48,7 @@ const Toast = (props: IToast) => {
|
|||
return (
|
||||
<Icon
|
||||
src={require('@tabler/icons/info-circle.svg')}
|
||||
className='w-6 h-6 text-primary-600 dark:text-accent-blue'
|
||||
className='h-6 w-6 text-primary-600 dark:text-accent-blue'
|
||||
aria-hidden
|
||||
/>
|
||||
);
|
||||
|
@ -56,7 +56,7 @@ const Toast = (props: IToast) => {
|
|||
return (
|
||||
<Icon
|
||||
src={require('@tabler/icons/alert-circle.svg')}
|
||||
className='w-6 h-6 text-danger-600'
|
||||
className='h-6 w-6 text-danger-600'
|
||||
aria-hidden
|
||||
/>
|
||||
);
|
||||
|
@ -112,7 +112,7 @@ const Toast = (props: IToast) => {
|
|||
<HStack space={4} alignItems='start'>
|
||||
<HStack space={3} justifyContent='between' alignItems='start' className='w-0 flex-1'>
|
||||
<HStack space={3} alignItems='start' className='w-0 flex-1'>
|
||||
<div className='flex-shrink-0'>
|
||||
<div className='shrink-0'>
|
||||
{renderIcon()}
|
||||
</div>
|
||||
|
||||
|
@ -126,15 +126,15 @@ const Toast = (props: IToast) => {
|
|||
</HStack>
|
||||
|
||||
{/* Dismiss Button */}
|
||||
<div className='flex flex-shrink-0 pt-0.5'>
|
||||
<div className='flex shrink-0 pt-0.5'>
|
||||
<button
|
||||
type='button'
|
||||
className='inline-flex rounded-md text-gray-600 dark:text-gray-600 hover:text-gray-700 dark:hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2'
|
||||
className='inline-flex rounded-md text-gray-600 hover:text-gray-700 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 dark:text-gray-600 dark:hover:text-gray-500'
|
||||
onClick={dismissToast}
|
||||
data-testid='toast-dismiss'
|
||||
>
|
||||
<span className='sr-only'>Close</span>
|
||||
<Icon src={require('@tabler/icons/x.svg')} className='w-5 h-5' />
|
||||
<Icon src={require('@tabler/icons/x.svg')} className='h-5 w-5' />
|
||||
</button>
|
||||
</div>
|
||||
</HStack>
|
||||
|
|
|
@ -49,7 +49,7 @@ const Widget: React.FC<IWidget> = ({
|
|||
<WidgetTitle title={title} />
|
||||
{action || (onActionClick && (
|
||||
<IconButton
|
||||
className='w-6 h-6 ml-2 text-black dark:text-white rtl:rotate-180'
|
||||
className='ml-2 h-6 w-6 text-black rtl:rotate-180 dark:text-white'
|
||||
src={actionIcon}
|
||||
onClick={onActionClick}
|
||||
title={actionTitle}
|
||||
|
|
|
@ -14,7 +14,7 @@ const UploadProgress: React.FC<IUploadProgress> = ({ progress }) => {
|
|||
<HStack alignItems='center' space={2}>
|
||||
<Icon
|
||||
src={require('@tabler/icons/cloud-upload.svg')}
|
||||
className='w-7 h-7 text-gray-500'
|
||||
className='h-7 w-7 text-gray-500'
|
||||
/>
|
||||
|
||||
<Stack space={1}>
|
||||
|
|
|
@ -141,7 +141,7 @@ const Upload: React.FC<IUpload> = ({
|
|||
|
||||
const uploadIcon = mediaType === 'unknown' && (
|
||||
<Icon
|
||||
className='h-16 w-16 mx-auto my-12 text-gray-800 dark:text-gray-200'
|
||||
className='mx-auto my-12 h-16 w-16 text-gray-800 dark:text-gray-200'
|
||||
src={MIMETYPE_ICONS[mimeType || ''] || defaultIcon}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -38,7 +38,7 @@ const AboutPage: React.FC = () => {
|
|||
<div>
|
||||
<FormattedMessage id='about.also_available' defaultMessage='Available in:' />
|
||||
{' '}
|
||||
<ul className='p-0 inline list-none'>
|
||||
<ul className='inline list-none p-0'>
|
||||
<li className="inline after:content-['_·_']">
|
||||
<a href='#' onClick={() => setLocale(defaultLocale)}>
|
||||
{/* @ts-ignore */}
|
||||
|
@ -60,7 +60,7 @@ const AboutPage: React.FC = () => {
|
|||
);
|
||||
|
||||
return (
|
||||
<div className='prose dark:prose-invert mx-auto py-20'>
|
||||
<div className='prose mx-auto py-20 dark:prose-invert'>
|
||||
<div dangerouslySetInnerHTML={{ __html: pageHtml }} />
|
||||
|
||||
{alsoAvailable}
|
||||
|
|
|
@ -71,7 +71,7 @@ const MediaItem: React.FC<IMediaItem> = ({ attachment, onOpenMedia }) => {
|
|||
src={attachment.preview_url}
|
||||
alt={attachment.description}
|
||||
style={{ objectPosition: `${x}% ${y}%` }}
|
||||
className='w-full h-full rounded-lg overflow-hidden'
|
||||
className='h-full w-full overflow-hidden rounded-lg'
|
||||
/>
|
||||
);
|
||||
} else if (['gifv', 'video'].indexOf(attachment.type) !== -1) {
|
||||
|
|
|
@ -17,7 +17,7 @@ const MovedNote: React.FC<IMovedNote> = ({ from, to }) => (
|
|||
<HStack className='mb-2' alignItems='center' space={1.5}>
|
||||
<Icon
|
||||
src={require('@tabler/icons/briefcase.svg')}
|
||||
className='text-primary-600 dark:text-primary-400 flex-none'
|
||||
className='flex-none text-primary-600 dark:text-primary-400'
|
||||
/>
|
||||
|
||||
<div className='truncate'>
|
||||
|
|
|
@ -102,16 +102,16 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
|
||||
if (!account) {
|
||||
return (
|
||||
<div className='-mt-4 -mx-4'>
|
||||
<div className='-mx-4 -mt-4'>
|
||||
<div>
|
||||
<div className='relative h-32 w-full lg:h-48 md:rounded-t-xl bg-gray-200 dark:bg-gray-900/50' />
|
||||
<div className='relative h-32 w-full bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48' />
|
||||
</div>
|
||||
|
||||
<div className='px-4 sm:px-6'>
|
||||
<HStack alignItems='bottom' space={5} className='-mt-12'>
|
||||
<div className='flex relative'>
|
||||
<div className='relative flex'>
|
||||
<div
|
||||
className='h-24 w-24 bg-gray-400 rounded-full ring-4 ring-white dark:ring-gray-800'
|
||||
className='h-24 w-24 rounded-full bg-gray-400 ring-4 ring-white dark:ring-gray-800'
|
||||
/>
|
||||
</div>
|
||||
</HStack>
|
||||
|
@ -586,13 +586,13 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
const menu = makeMenu();
|
||||
|
||||
return (
|
||||
<div className='-mt-4 -mx-4'>
|
||||
<div className='-mx-4 -mt-4'>
|
||||
{(account.moved && typeof account.moved === 'object') && (
|
||||
<MovedNote from={account} to={account.moved} />
|
||||
)}
|
||||
|
||||
<div>
|
||||
<div className='relative flex flex-col justify-center h-32 w-full lg:h-48 md:rounded-t-xl bg-gray-200 dark:bg-gray-900/50 overflow-hidden isolate'>
|
||||
<div className='relative isolate flex h-32 w-full flex-col justify-center overflow-hidden bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48'>
|
||||
{renderHeader()}
|
||||
|
||||
<div className='absolute top-2 left-2'>
|
||||
|
@ -610,12 +610,12 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
<Avatar
|
||||
src={account.avatar}
|
||||
size={96}
|
||||
className='relative h-24 w-24 rounded-full ring-4 ring-white dark:ring-primary-900 bg-white dark:bg-primary-900'
|
||||
className='relative h-24 w-24 rounded-full bg-white ring-4 ring-white dark:bg-primary-900 dark:ring-primary-900'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className='mt-6 flex justify-end w-full sm:pb-1'>
|
||||
<div className='mt-6 flex w-full justify-end sm:pb-1'>
|
||||
<HStack space={2} className='mt-10'>
|
||||
<SubscriptionButton account={account} />
|
||||
{renderMessageButton()}
|
||||
|
@ -644,7 +644,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
<Comp key={idx} {...itemProps} className='group'>
|
||||
<HStack space={3} alignItems='center'>
|
||||
{menuItem.icon && (
|
||||
<SvgIcon src={menuItem.icon} className='h-5 w-5 text-gray-400 flex-none group-hover:text-gray-500' />
|
||||
<SvgIcon src={menuItem.icon} className='h-5 w-5 flex-none text-gray-400 group-hover:text-gray-500' />
|
||||
)}
|
||||
|
||||
<div className='truncate'>{menuItem.text}</div>
|
||||
|
|
|
@ -21,7 +21,7 @@ const DashCounter: React.FC<IDashCounter> = ({ count, label, to = '#', percent =
|
|||
|
||||
return (
|
||||
<Link
|
||||
className='bg-gray-200 dark:bg-gray-800 p-4 rounded flex flex-col items-center space-y-2 hover:-translate-y-1 transition-transform cursor-pointer'
|
||||
className='flex cursor-pointer flex-col items-center space-y-2 rounded bg-gray-200 p-4 transition-transform hover:-translate-y-1 dark:bg-gray-800'
|
||||
to={to}
|
||||
>
|
||||
<Text align='center' size='2xl' weight='medium'>
|
||||
|
@ -45,7 +45,7 @@ interface IDashCounters {
|
|||
/** Wrapper container for dash counters. */
|
||||
const DashCounters: React.FC<IDashCounters> = ({ children }) => {
|
||||
return (
|
||||
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2'>
|
||||
<div className='grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-3'>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -135,7 +135,7 @@ const Report: React.FC<IReport> = ({ id }) => {
|
|||
<Link
|
||||
to={`/@${reporterAcct}`}
|
||||
title={reporterAcct}
|
||||
className='text-primary-600 dark:text-accent-blue hover:underline'
|
||||
className='text-primary-600 hover:underline dark:text-accent-blue'
|
||||
>
|
||||
@{reporterAcct}
|
||||
</Link>
|
||||
|
|
|
@ -115,13 +115,13 @@ const Dashboard: React.FC = () => {
|
|||
<ListItem label={<FormattedMessage id='admin.software.frontend' defaultMessage='Frontend' />}>
|
||||
<a
|
||||
href={sourceCode.ref ? `${sourceCode.url}/tree/${sourceCode.ref}` : sourceCode.url}
|
||||
className='flex space-x-1 items-center truncate'
|
||||
className='flex items-center space-x-1 truncate'
|
||||
target='_blank'
|
||||
>
|
||||
<span>{sourceCode.displayName} {sourceCode.version}</span>
|
||||
|
||||
<Icon
|
||||
className='w-4 h-4'
|
||||
className='h-4 w-4'
|
||||
src={require('@tabler/icons/external-link.svg')}
|
||||
/>
|
||||
</a>
|
||||
|
|
|
@ -85,7 +85,7 @@ const Ad: React.FC<IAd> = ({ ad }) => {
|
|||
</Text>
|
||||
|
||||
<Icon
|
||||
className='w-5 h-5 stroke-accent-500'
|
||||
className='h-5 w-5 stroke-accent-500'
|
||||
src={require('@tabler/icons/timeline.svg')}
|
||||
/>
|
||||
</HStack>
|
||||
|
|
|
@ -40,11 +40,11 @@ const Search: React.FC = () => {
|
|||
|
||||
return (
|
||||
<div className='flex items-center gap-1'>
|
||||
<label className='flex-grow relative'>
|
||||
<label className='relative grow'>
|
||||
<span style={{ display: 'none' }}>{intl.formatMessage(messages.search)}</span>
|
||||
|
||||
<input
|
||||
className='block w-full sm:text-sm dark:bg-gray-800 dark:text-white dark:placeholder:text-gray-500 focus:ring-primary-500 focus:border-primary-500 rounded-full'
|
||||
className='block w-full rounded-full focus:border-primary-500 focus:ring-primary-500 dark:bg-gray-800 dark:text-white dark:placeholder:text-gray-500 sm:text-sm'
|
||||
type='text'
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
|
|
|
@ -36,9 +36,9 @@ const AuthLayout = () => {
|
|||
<LandingGradient />
|
||||
|
||||
<main className='relative h-full sm:flex sm:justify-center'>
|
||||
<div className='w-full h-full flex flex-col sm:max-w-lg md:max-w-2xl lg:max-w-6xl'>
|
||||
<header className='flex justify-between relative py-12 px-2 mb-auto'>
|
||||
<div className='relative z-0 flex-1 px-2 lg:flex lg:items-center lg:justify-center lg:absolute lg:inset-0'>
|
||||
<div className='flex h-full w-full flex-col sm:max-w-lg md:max-w-2xl lg:max-w-6xl'>
|
||||
<header className='relative mb-auto flex justify-between py-12 px-2'>
|
||||
<div className='relative z-0 flex-1 px-2 lg:absolute lg:inset-0 lg:flex lg:items-center lg:justify-center'>
|
||||
<Link to='/' className='cursor-pointer'>
|
||||
<SiteLogo alt={instance.title} className='h-7' />
|
||||
</Link>
|
||||
|
@ -57,8 +57,8 @@ const AuthLayout = () => {
|
|||
)}
|
||||
</header>
|
||||
|
||||
<div className='flex flex-col justify-center items-center'>
|
||||
<div className='pb-10 sm:mx-auto w-full sm:max-w-lg md:max-w-2xl'>
|
||||
<div className='flex flex-col items-center justify-center'>
|
||||
<div className='w-full pb-10 sm:mx-auto sm:max-w-lg md:max-w-2xl'>
|
||||
<Card variant='rounded' size='xl'>
|
||||
<CardBody>
|
||||
<Switch>
|
||||
|
|
|
@ -109,7 +109,7 @@ const NativeCaptchaField: React.FC<INativeCaptchaField> = ({ captcha, onChange,
|
|||
|
||||
return (
|
||||
<Stack space={2}>
|
||||
<div className='flex items-center justify-center bg-white w-full border border-solid border-gray-300 dark:border-gray-600 rounded-md'>
|
||||
<div className='flex w-full items-center justify-center rounded-md border border-solid border-gray-300 bg-white dark:border-gray-600'>
|
||||
<img alt='captcha' src={captcha.get('url')} onClick={onClick} />
|
||||
</div>
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ const ConsumersList: React.FC<IConsumersList> = () => {
|
|||
|
||||
if (providers.size > 0) {
|
||||
return (
|
||||
<Card className='p-4 sm:rounded-xl bg-gray-50 dark:bg-primary-800'>
|
||||
<Card className='bg-gray-50 p-4 dark:bg-primary-800 sm:rounded-xl'>
|
||||
<Text size='xs' theme='muted'>
|
||||
<FormattedMessage id='oauth_consumers.title' defaultMessage='Other ways to sign in' />
|
||||
</Text>
|
||||
|
|
|
@ -27,11 +27,11 @@ const LoginForm: React.FC<ILoginForm> = ({ isLoading, handleSubmit }) => {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<div className='pb-4 sm:pb-10 mb-4 border-b border-gray-200 dark:border-gray-800 border-solid -mx-4 sm:-mx-10'>
|
||||
<h1 className='text-center font-bold text-2xl'><FormattedMessage id='login_form.header' defaultMessage='Sign In' /></h1>
|
||||
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-800 sm:-mx-10 sm:pb-10'>
|
||||
<h1 className='text-center text-2xl font-bold'><FormattedMessage id='login_form.header' defaultMessage='Sign In' /></h1>
|
||||
</div>
|
||||
|
||||
<Stack className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto' space={5}>
|
||||
<Stack className='mx-auto sm:w-2/3 sm:pt-10 md:w-1/2' space={5}>
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<FormGroup labelText={intl.formatMessage(messages.username)}>
|
||||
<Input
|
||||
|
|
|
@ -48,13 +48,13 @@ const OtpAuthForm: React.FC<IOtpAuthForm> = ({ mfa_token }) => {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<div className='pb-4 sm:pb-10 mb-4 border-b border-gray-200 dark:border-gray-600 border-solid -mx-4 sm:-mx-10'>
|
||||
<h1 className='text-center font-bold text-2xl'>
|
||||
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-600 sm:-mx-10 sm:pb-10'>
|
||||
<h1 className='text-center text-2xl font-bold'>
|
||||
<FormattedMessage id='login.otp_log_in' defaultMessage='OTP Login' />
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||
<div className='mx-auto sm:w-2/3 sm:pt-10 md:w-1/2'>
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<FormGroup
|
||||
labelText={intl.formatMessage(messages.otpCodeLabel)}
|
||||
|
|
|
@ -59,13 +59,13 @@ const PasswordResetConfirm = () => {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<div className='pb-4 sm:pb-10 mb-4 border-b border-gray-200 dark:border-gray-600 border-solid -mx-4 sm:-mx-10'>
|
||||
<h1 className='text-center font-bold text-2xl'>
|
||||
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-600 sm:-mx-10 sm:pb-10'>
|
||||
<h1 className='text-center text-2xl font-bold'>
|
||||
<FormattedMessage id='reset_password.header' defaultMessage='Set New Password' />
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||
<div className='mx-auto sm:w-2/3 sm:pt-10 md:w-1/2'>
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<FormGroup labelText={<FormattedMessage id='reset_password.password.label' defaultMessage='Password' />} errors={renderErrors()}>
|
||||
<Input
|
||||
|
|
|
@ -35,13 +35,13 @@ const PasswordReset = () => {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<div className='pb-4 sm:pb-10 mb-4 border-b border-gray-200 dark:border-gray-600 border-solid -mx-4 sm:-mx-10'>
|
||||
<h1 className='text-center font-bold text-2xl'>
|
||||
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-600 sm:-mx-10 sm:pb-10'>
|
||||
<h1 className='text-center text-2xl font-bold'>
|
||||
<FormattedMessage id='password_reset.header' defaultMessage='Reset Password' />
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||
<div className='mx-auto sm:w-2/3 sm:pt-10 md:w-1/2'>
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<FormGroup labelText={intl.formatMessage(messages.nicknameOrEmail)}>
|
||||
<Input
|
||||
|
|
|
@ -41,7 +41,7 @@ const AuthToken: React.FC<IAuthToken> = ({ token, isCurrent }) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className='p-4 rounded-lg bg-gray-100 dark:bg-primary-800'>
|
||||
<div className='rounded-lg bg-gray-100 p-4 dark:bg-primary-800'>
|
||||
<Stack space={2}>
|
||||
<Stack>
|
||||
<Text size='md' weight='medium'>{token.app_name}</Text>
|
||||
|
@ -85,7 +85,7 @@ const AuthTokenList: React.FC = () => {
|
|||
}, []);
|
||||
|
||||
const body = tokens ? (
|
||||
<div className='grid grid-cols-1 sm:grid-cols-2 gap-4'>
|
||||
<div className='grid grid-cols-1 gap-4 sm:grid-cols-2'>
|
||||
{tokens.map((token) => (
|
||||
<AuthToken key={token.id} token={token} isCurrent={token.id === currentTokenId} />
|
||||
))}
|
||||
|
|
|
@ -166,7 +166,7 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
|
|||
|
||||
<HStack alignItems='stretch' justifyContent='between' space={4}>
|
||||
{features.chatsMedia && (
|
||||
<Stack justifyContent='end' alignItems='center' className='w-10 mb-1.5'>
|
||||
<Stack justifyContent='end' alignItems='center' className='mb-1.5 w-10'>
|
||||
<UploadButton
|
||||
onSelectFile={onSelectFile}
|
||||
resetFileKey={resetFileKey}
|
||||
|
@ -216,7 +216,7 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
|
|||
</Combobox>
|
||||
</Stack>
|
||||
|
||||
<Stack space={2} justifyContent='end' alignItems='center' className='w-10 mb-1.5'>
|
||||
<Stack space={2} justifyContent='end' alignItems='center' className='mb-1.5 w-10'>
|
||||
{isOverCharacterLimit ? (
|
||||
<Text size='sm' theme='danger'>{overLimitText}</Text>
|
||||
) : null}
|
||||
|
|
|
@ -68,7 +68,7 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
|
|||
role='button'
|
||||
key={chat.id}
|
||||
onClick={() => onClick(chat)}
|
||||
className='group px-2 py-3 w-full flex flex-col rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 focus:shadow-inset-ring'
|
||||
className='group flex w-full flex-col rounded-lg px-2 py-3 hover:bg-gray-100 focus:shadow-inset-ring dark:hover:bg-gray-800'
|
||||
data-testid='chat-list-item'
|
||||
>
|
||||
<HStack alignItems='center' justifyContent='between' space={2} className='w-full'>
|
||||
|
@ -76,7 +76,7 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
|
|||
<Avatar src={chat.account?.avatar} size={40} className='flex-none' />
|
||||
|
||||
<Stack alignItems='start' className='overflow-hidden'>
|
||||
<div className='flex items-center space-x-1 flex-grow w-full'>
|
||||
<div className='flex w-full grow items-center space-x-1'>
|
||||
<Text weight='bold' size='sm' align='left' truncate>{chat.account?.display_name || `@${chat.account.username}`}</Text>
|
||||
{chat.account?.verified && <VerificationBadge />}
|
||||
</div>
|
||||
|
@ -88,7 +88,7 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
|
|||
weight='medium'
|
||||
theme='muted'
|
||||
truncate
|
||||
className='w-full h-5 pointer-events-none italic'
|
||||
className='pointer-events-none h-5 w-full italic'
|
||||
data-testid='chat-last-message'
|
||||
>
|
||||
{intl.formatMessage(isBlocked ? messages.blockedYou : messages.blocking)}
|
||||
|
@ -102,7 +102,7 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
|
|||
weight='medium'
|
||||
theme={chat.last_message.unread ? 'default' : 'muted'}
|
||||
truncate
|
||||
className='w-full h-5 truncate-child pointer-events-none'
|
||||
className='truncate-child pointer-events-none h-5 w-full'
|
||||
data-testid='chat-last-message'
|
||||
dangerouslySetInnerHTML={{ __html: chat.last_message?.content }}
|
||||
/>
|
||||
|
@ -114,12 +114,12 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
|
|||
|
||||
<HStack alignItems='center' space={2}>
|
||||
{features.chatsDelete && (
|
||||
<div className='text-gray-600 hidden group-hover:block hover:text-gray-100'>
|
||||
<div className='hidden text-gray-600 hover:text-gray-100 group-hover:block'>
|
||||
<DropdownMenuContainer items={menu}>
|
||||
<IconButton
|
||||
src={require('@tabler/icons/dots.svg')}
|
||||
title='Settings'
|
||||
className='text-gray-600 dark:text-gray-600 hover:text-gray-700 dark:hover:text-gray-500'
|
||||
className='text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-500'
|
||||
iconClassName='w-4 h-4'
|
||||
/>
|
||||
</DropdownMenuContainer>
|
||||
|
@ -130,7 +130,7 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
|
|||
<>
|
||||
{chat.last_message.unread && (
|
||||
<div
|
||||
className='w-2 h-2 rounded-full bg-secondary-500'
|
||||
className='h-2 w-2 rounded-full bg-secondary-500'
|
||||
data-testid='chat-unread-indicator'
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -106,8 +106,8 @@ const ChatMessageListIntro = () => {
|
|||
</Button>
|
||||
</HStack>
|
||||
) : (
|
||||
<HStack justifyContent='center' alignItems='center' space={1} className='flex-shrink-0'>
|
||||
<Icon src={require('@tabler/icons/clock.svg')} className='text-gray-600 w-4 h-4' />
|
||||
<HStack justifyContent='center' alignItems='center' space={1} className='shrink-0'>
|
||||
<Icon src={require('@tabler/icons/clock.svg')} className='h-4 w-4 text-gray-600' />
|
||||
{chat.message_expiration && (
|
||||
<Text size='sm' theme='muted'>
|
||||
{intl.formatMessage(messages.messageLifespan, { day: secondsToDays(chat.message_expiration) })}
|
||||
|
|
|
@ -304,7 +304,7 @@ const ChatMessageList: React.FC<IChatMessageList> = ({ chat }) => {
|
|||
<IconButton
|
||||
src={require('@tabler/icons/dots.svg')}
|
||||
title={intl.formatMessage(messages.more)}
|
||||
className='text-gray-600 dark:text-gray-600 hover:text-gray-700 dark:hover:text-gray-500'
|
||||
className='text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-500'
|
||||
iconClassName='w-4 h-4'
|
||||
/>
|
||||
</DropdownMenuContainer>
|
||||
|
@ -378,12 +378,12 @@ const ChatMessageList: React.FC<IChatMessageList> = ({ chat }) => {
|
|||
{(isMyMessage && features.chatsReadReceipts) ? (
|
||||
<>
|
||||
{isRead ? (
|
||||
<span className='rounded-full flex flex-col items-center justify-center p-0.5 bg-primary-500 text-white dark:bg-primary-400 dark:text-primary-900 border border-solid border-primary-500 dark:border-primary-400'>
|
||||
<Icon src={require('@tabler/icons/check.svg')} strokeWidth={3} className='w-2.5 h-2.5' />
|
||||
<span className='flex flex-col items-center justify-center rounded-full border border-solid border-primary-500 bg-primary-500 p-0.5 text-white dark:border-primary-400 dark:bg-primary-400 dark:text-primary-900'>
|
||||
<Icon src={require('@tabler/icons/check.svg')} strokeWidth={3} className='h-2.5 w-2.5' />
|
||||
</span>
|
||||
) : (
|
||||
<span className='rounded-full flex flex-col items-center justify-center p-0.5 bg-transparent text-primary-500 dark:text-primary-400 border border-solid border-primary-500 dark:border-primary-400'>
|
||||
<Icon src={require('@tabler/icons/check.svg')} strokeWidth={3} className='w-2.5 h-2.5' />
|
||||
<span className='flex flex-col items-center justify-center rounded-full border border-solid border-primary-500 bg-transparent p-0.5 text-primary-500 dark:border-primary-400 dark:text-primary-400'>
|
||||
<Icon src={require('@tabler/icons/check.svg')} strokeWidth={3} className='h-2.5 w-2.5' />
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
|
@ -418,7 +418,7 @@ const ChatMessageList: React.FC<IChatMessageList> = ({ chat }) => {
|
|||
|
||||
if (isBlocked) {
|
||||
return (
|
||||
<Stack alignItems='center' justifyContent='center' className='h-full flex-grow'>
|
||||
<Stack alignItems='center' justifyContent='center' className='h-full grow'>
|
||||
<Stack alignItems='center' space={2}>
|
||||
<Avatar src={chat.account.avatar} size={75} />
|
||||
<Text align='center'>
|
||||
|
@ -435,7 +435,7 @@ const ChatMessageList: React.FC<IChatMessageList> = ({ chat }) => {
|
|||
|
||||
if (isError) {
|
||||
return (
|
||||
<Stack alignItems='center' justifyContent='center' className='h-full flex-grow'>
|
||||
<Stack alignItems='center' justifyContent='center' className='h-full grow'>
|
||||
<Stack space={4}>
|
||||
<Stack space={1}>
|
||||
<Text size='lg' weight='bold' align='center'>
|
||||
|
@ -458,7 +458,7 @@ const ChatMessageList: React.FC<IChatMessageList> = ({ chat }) => {
|
|||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className='flex-grow flex flex-col justify-end pb-4'>
|
||||
<div className='flex grow flex-col justify-end pb-4'>
|
||||
<div className='px-4'>
|
||||
<PlaceholderChatMessage isMyMessage />
|
||||
<PlaceholderChatMessage />
|
||||
|
@ -471,8 +471,8 @@ const ChatMessageList: React.FC<IChatMessageList> = ({ chat }) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className='h-full flex flex-col flex-grow space-y-6'>
|
||||
<div className='flex-grow flex flex-col justify-end'>
|
||||
<div className='flex h-full grow flex-col space-y-6'>
|
||||
<div className='flex grow flex-col justify-end'>
|
||||
<Virtuoso
|
||||
ref={node}
|
||||
alignToBottom
|
||||
|
|
|
@ -60,11 +60,11 @@ const ChatPage: React.FC<IChatPage> = ({ chatId }) => {
|
|||
<div
|
||||
ref={containerRef}
|
||||
style={{ height }}
|
||||
className='h-screen bg-white dark:bg-primary-900 text-gray-900 dark:text-gray-100 shadow-lg dark:shadow-none overflow-hidden sm:rounded-t-xl'
|
||||
className='h-screen overflow-hidden bg-white text-gray-900 shadow-lg dark:bg-primary-900 dark:text-gray-100 dark:shadow-none sm:rounded-t-xl'
|
||||
>
|
||||
{isOnboarded ? (
|
||||
<div
|
||||
className='grid grid-cols-9 overflow-hidden h-full dark:divide-x-2 dark:divide-solid dark:divide-gray-800'
|
||||
className='grid h-full grid-cols-9 overflow-hidden dark:divide-x-2 dark:divide-solid dark:divide-gray-800'
|
||||
data-testid='chat-page'
|
||||
>
|
||||
<Stack
|
||||
|
|
|
@ -16,7 +16,7 @@ const BlankslateEmpty: React.FC<IBlankslate> = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Stack space={6} alignItems='center' justifyContent='center' className='p-6 h-full'>
|
||||
<Stack space={6} alignItems='center' justifyContent='center' className='h-full p-6'>
|
||||
<Stack space={2} className='max-w-sm'>
|
||||
<Text size='2xl' weight='bold' tag='h2' align='center'>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -13,7 +13,7 @@ const BlankslateWithChats = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Stack space={6} alignItems='center' justifyContent='center' className='p-6 h-full'>
|
||||
<Stack space={6} alignItems='center' justifyContent='center' className='h-full p-6'>
|
||||
<Stack space={2} className='max-w-sm'>
|
||||
<Text size='2xl' weight='bold' tag='h2' align='center'>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -116,12 +116,12 @@ const ChatPageMain = () => {
|
|||
|
||||
return (
|
||||
<Stack className='h-full overflow-hidden'>
|
||||
<HStack alignItems='center' justifyContent='between' space={2} className='px-4 py-4 w-full'>
|
||||
<HStack alignItems='center' justifyContent='between' space={2} className='w-full p-4'>
|
||||
<HStack alignItems='center' space={2} className='overflow-hidden'>
|
||||
<HStack alignItems='center'>
|
||||
<IconButton
|
||||
src={require('@tabler/icons/arrow-left.svg')}
|
||||
className='sm:hidden h-7 w-7 mr-2 sm:mr-0'
|
||||
className='mr-2 h-7 w-7 sm:mr-0 sm:hidden'
|
||||
onClick={() => history.push('/chats')}
|
||||
/>
|
||||
|
||||
|
@ -130,8 +130,8 @@ const ChatPageMain = () => {
|
|||
</Link>
|
||||
</HStack>
|
||||
|
||||
<Stack alignItems='start' className='overflow-hidden h-11'>
|
||||
<div className='flex items-center space-x-1 flex-grow w-full'>
|
||||
<Stack alignItems='start' className='h-11 overflow-hidden'>
|
||||
<div className='flex w-full grow items-center space-x-1'>
|
||||
<Link to={`/@${chat.account.acct}`}>
|
||||
<Text weight='bold' size='sm' align='left' truncate>
|
||||
{chat.account.display_name || `@${chat.account.username}`}
|
||||
|
@ -212,8 +212,8 @@ const ChatPageMain = () => {
|
|||
onSelect={isBlocking ? handleUnblockUser : handleBlockUser}
|
||||
className='!px-0 hover:!bg-transparent'
|
||||
>
|
||||
<div className='w-full flex items-center space-x-2 font-bold text-sm text-primary-500 dark:text-accent-blue'>
|
||||
<Icon src={require('@tabler/icons/ban.svg')} className='w-5 h-5' />
|
||||
<div className='flex w-full items-center space-x-2 text-sm font-bold text-primary-500 dark:text-accent-blue'>
|
||||
<Icon src={require('@tabler/icons/ban.svg')} className='h-5 w-5' />
|
||||
<span>{intl.formatMessage(isBlocking ? messages.unblockUser : messages.blockUser, { acct: chat.account.acct })}</span>
|
||||
</div>
|
||||
</MenuItem>
|
||||
|
@ -224,8 +224,8 @@ const ChatPageMain = () => {
|
|||
onSelect={handleLeaveChat}
|
||||
className='!px-0 hover:!bg-transparent'
|
||||
>
|
||||
<div className='w-full flex items-center space-x-2 font-bold text-sm text-danger-600 dark:text-danger-500'>
|
||||
<Icon src={require('@tabler/icons/logout.svg')} className='w-5 h-5' />
|
||||
<div className='flex w-full items-center space-x-2 text-sm font-bold text-danger-600 dark:text-danger-500'>
|
||||
<Icon src={require('@tabler/icons/logout.svg')} className='h-5 w-5' />
|
||||
<span>{intl.formatMessage(messages.leaveChat)}</span>
|
||||
</div>
|
||||
</MenuItem>
|
||||
|
|
|
@ -20,11 +20,11 @@ const ChatPageNew: React.FC<IChatPageNew> = () => {
|
|||
|
||||
return (
|
||||
<Stack className='h-full space-y-4'>
|
||||
<Stack className='flex-grow pt-6 px-4 sm:px-6'>
|
||||
<Stack className='grow px-4 pt-6 sm:px-6'>
|
||||
<HStack alignItems='center'>
|
||||
<IconButton
|
||||
src={require('@tabler/icons/arrow-left.svg')}
|
||||
className='sm:hidden h-7 w-7 mr-2 sm:mr-0'
|
||||
className='mr-2 h-7 w-7 sm:mr-0 sm:hidden'
|
||||
onClick={() => history.push('/chats')}
|
||||
/>
|
||||
|
||||
|
|
|
@ -47,11 +47,11 @@ const ChatPageSettings = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Stack className='h-full py-6 px-4 sm:p-6 space-y-8'>
|
||||
<Stack className='h-full space-y-8 py-6 px-4 sm:p-6'>
|
||||
<HStack alignItems='center'>
|
||||
<IconButton
|
||||
src={require('@tabler/icons/arrow-left.svg')}
|
||||
className='sm:hidden h-7 w-7 mr-2 sm:mr-0'
|
||||
className='mr-2 h-7 w-7 sm:mr-0 sm:hidden'
|
||||
onClick={() => history.push('/chats')}
|
||||
/>
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ const ChatPageSidebar = () => {
|
|||
)}
|
||||
</Stack>
|
||||
|
||||
<Stack className='flex-grow h-full'>
|
||||
<Stack className='h-full grow'>
|
||||
<ChatList
|
||||
onClickChat={handleClickChat}
|
||||
searchValue={debouncedSearch}
|
||||
|
|
|
@ -36,9 +36,9 @@ const Welcome = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Stack className='py-20 px-4 sm:px-0 h-full overflow-y-auto' data-testid='chats-welcome'>
|
||||
<div className='w-full sm:w-3/5 xl:w-2/5 mx-auto mb-2.5'>
|
||||
<Text align='center' weight='bold' className='mb-6 text-2xl md:text-3xl leading-8'>
|
||||
<Stack className='h-full overflow-y-auto py-20 px-4 sm:px-0' data-testid='chats-welcome'>
|
||||
<div className='mx-auto mb-2.5 w-full sm:w-3/5 xl:w-2/5'>
|
||||
<Text align='center' weight='bold' className='mb-6 text-2xl leading-8 md:text-3xl'>
|
||||
{intl.formatMessage(messages.title, { br: <br /> })}
|
||||
</Text>
|
||||
|
||||
|
@ -47,7 +47,7 @@ const Welcome = () => {
|
|||
</Text>
|
||||
</div>
|
||||
|
||||
<Form onSubmit={handleSubmit} className='space-y-8 w-full sm:w-2/3 lg:w-3/5 sm:mx-auto'>
|
||||
<Form onSubmit={handleSubmit} className='w-full space-y-8 sm:mx-auto sm:w-2/3 lg:w-3/5'>
|
||||
<Stack space={2}>
|
||||
<CardTitle title={<FormattedMessage id='chat.page_settings.privacy' defaultMessage='Privacy' />} />
|
||||
|
||||
|
|
|
@ -20,11 +20,11 @@ const Blankslate = ({ onSearch }: IBlankslate) => {
|
|||
<Stack
|
||||
alignItems='center'
|
||||
justifyContent='center'
|
||||
className='h-full flex-grow'
|
||||
className='h-full grow'
|
||||
data-testid='chat-pane-blankslate'
|
||||
>
|
||||
<Stack space={4}>
|
||||
<Stack space={1} className='max-w-[80%] mx-auto'>
|
||||
<Stack space={1} className='mx-auto max-w-[80%]'>
|
||||
<Text size='lg' weight='bold' align='center'>
|
||||
{intl.formatMessage(messages.title)}
|
||||
</Text>
|
||||
|
|
|
@ -45,7 +45,7 @@ const ChatPane = () => {
|
|||
const renderBody = () => {
|
||||
if (hasSearchValue || Number(chats?.length) > 0 || isLoading) {
|
||||
return (
|
||||
<Stack space={4} className='flex-grow h-full'>
|
||||
<Stack space={4} className='h-full grow'>
|
||||
{features.chatsSearch && (
|
||||
<div className='px-4'>
|
||||
<ChatSearchInput
|
||||
|
|
|
@ -9,7 +9,7 @@ interface IChatPendingUpload {
|
|||
/** Displays a loading thumbnail for an upload in the chat composer. */
|
||||
const ChatPendingUpload: React.FC<IChatPendingUpload> = ({ progress }) => {
|
||||
return (
|
||||
<div className='relative p-4 inline-flex items-center justify-center w-24 h-24 rounded-lg overflow-hidden isolate bg-gray-200 dark:bg-primary-900'>
|
||||
<div className='relative isolate inline-flex h-24 w-24 items-center justify-center overflow-hidden rounded-lg bg-gray-200 p-4 dark:bg-primary-900'>
|
||||
<ProgressBar progress={progress} size='sm' />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -12,7 +12,7 @@ const Blankslate = () => {
|
|||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Stack justifyContent='center' alignItems='center' space={2} className='h-full w-2/3 mx-auto'>
|
||||
<Stack justifyContent='center' alignItems='center' space={2} className='mx-auto h-full w-2/3'>
|
||||
<Text weight='bold' size='lg' align='center'>
|
||||
{intl.formatMessage(messages.title)}
|
||||
</Text>
|
||||
|
|
|
@ -88,7 +88,7 @@ const ChatSearch = (props: IChatSearch) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Stack space={4} className='flex-grow h-full'>
|
||||
<Stack space={4} className='h-full grow'>
|
||||
<div className='px-4'>
|
||||
<Input
|
||||
data-testid='search'
|
||||
|
@ -111,7 +111,7 @@ const ChatSearch = (props: IChatSearch) => {
|
|||
/>
|
||||
</div>
|
||||
|
||||
<Stack className='flex-grow'>
|
||||
<Stack className='grow'>
|
||||
{renderBody()}
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
|
|
@ -12,7 +12,7 @@ const EmptyResultsBlankslate = () => {
|
|||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Stack justifyContent='center' alignItems='center' space={2} className='h-full w-2/3 mx-auto'>
|
||||
<Stack justifyContent='center' alignItems='center' space={2} className='mx-auto h-full w-2/3'>
|
||||
<Text weight='bold' size='lg' align='center' data-testid='no-results'>
|
||||
{intl.formatMessage(messages.title)}
|
||||
</Text>
|
||||
|
|
|
@ -29,7 +29,7 @@ const Results = ({ accountSearchResult, onSelect }: IResults) => {
|
|||
<button
|
||||
key={account.id}
|
||||
type='button'
|
||||
className='px-2 py-3 w-full rounded-lg flex flex-col hover:bg-gray-100 dark:hover:bg-gray-800'
|
||||
className='flex w-full flex-col rounded-lg px-2 py-3 hover:bg-gray-100 dark:hover:bg-gray-800'
|
||||
onClick={() => onSelect(account.id)}
|
||||
data-testid='account'
|
||||
>
|
||||
|
@ -37,7 +37,7 @@ const Results = ({ accountSearchResult, onSelect }: IResults) => {
|
|||
<Avatar src={account.avatar} size={40} />
|
||||
|
||||
<Stack alignItems='start'>
|
||||
<div className='flex items-center space-x-1 flex-grow'>
|
||||
<div className='flex grow items-center space-x-1'>
|
||||
<Text weight='bold' size='sm' truncate>{account.display_name}</Text>
|
||||
{account.verified && <VerificationBadge />}
|
||||
</div>
|
||||
|
@ -48,7 +48,7 @@ const Results = ({ accountSearchResult, onSelect }: IResults) => {
|
|||
), []);
|
||||
|
||||
return (
|
||||
<div className='relative flex-grow'>
|
||||
<div className='relative grow'>
|
||||
<Virtuoso
|
||||
data={accounts}
|
||||
itemContent={(index, chat) => (
|
||||
|
|
|
@ -23,15 +23,15 @@ const ChatTextarea: React.FC<IChatTextarea> = ({
|
|||
}) => {
|
||||
return (
|
||||
<div className={`
|
||||
bg-white
|
||||
dark:bg-gray-800
|
||||
shadow-sm block w-full
|
||||
sm:text-sm rounded-md
|
||||
text-gray-900 dark:text-gray-100
|
||||
border
|
||||
placeholder:text-gray-600 dark:placeholder:text-gray-600 border-gray-400 dark:border-gray-800
|
||||
dark:ring-1 focus-within:ring-1 dark:ring-gray-800 focus-within:ring-primary-500 focus-within:border-primary-500
|
||||
dark:focus-within:ring-primary-500 dark:focus-within:border-primary-500
|
||||
block
|
||||
w-full
|
||||
rounded-md border border-gray-400
|
||||
bg-white text-gray-900
|
||||
shadow-sm placeholder:text-gray-600
|
||||
focus-within:border-primary-500
|
||||
focus-within:ring-1 focus-within:ring-primary-500 dark:border-gray-800 dark:bg-gray-800
|
||||
dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500
|
||||
dark:focus-within:ring-primary-500 sm:text-sm
|
||||
`}
|
||||
>
|
||||
{(!!attachments?.length || isUploading) && (
|
||||
|
|
|
@ -23,7 +23,7 @@ const ChatUploadPreview: React.FC<IChatUploadPreview> = ({ className, attachment
|
|||
case 'image':
|
||||
return (
|
||||
<img
|
||||
className='w-full h-full object-cover pointer-events-none'
|
||||
className='pointer-events-none h-full w-full object-cover'
|
||||
src={attachment.preview_url}
|
||||
alt=''
|
||||
/>
|
||||
|
@ -31,7 +31,7 @@ const ChatUploadPreview: React.FC<IChatUploadPreview> = ({ className, attachment
|
|||
case 'video':
|
||||
return (
|
||||
<video
|
||||
className='w-full h-full object-cover pointer-events-none'
|
||||
className='pointer-events-none h-full w-full object-cover'
|
||||
src={attachment.preview_url}
|
||||
autoPlay
|
||||
playsInline
|
||||
|
@ -42,9 +42,9 @@ const ChatUploadPreview: React.FC<IChatUploadPreview> = ({ className, attachment
|
|||
);
|
||||
default:
|
||||
return (
|
||||
<div className='w-full h-full flex items-center justify-center pointer-events-none'>
|
||||
<div className='pointer-events-none flex h-full w-full items-center justify-center'>
|
||||
<Icon
|
||||
className='h-16 w-16 mx-auto my-12 text-gray-800 dark:text-gray-200'
|
||||
className='mx-auto my-12 h-16 w-16 text-gray-800 dark:text-gray-200'
|
||||
src={MIMETYPE_ICONS[mimeType || ''] || defaultIcon}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -26,8 +26,8 @@ const ChatUpload: React.FC<IChatUpload> = ({ attachment, onDelete }) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className='relative inline-block w-24 h-24 rounded-lg overflow-hidden isolate bg-gray-200 dark:bg-primary-900'>
|
||||
<Blurhash hash={attachment.blurhash} className='absolute inset-0 w-full h-full -z-10' />
|
||||
<div className='relative isolate inline-block h-24 w-24 overflow-hidden rounded-lg bg-gray-200 dark:bg-primary-900'>
|
||||
<Blurhash hash={attachment.blurhash} className='absolute inset-0 -z-10 h-full w-full' />
|
||||
|
||||
<div className='absolute right-[6px] top-[6px]'>
|
||||
<RemoveButton onClick={onDelete} />
|
||||
|
@ -35,7 +35,7 @@ const ChatUpload: React.FC<IChatUpload> = ({ attachment, onDelete }) => {
|
|||
|
||||
<button
|
||||
onClick={clickable ? handleOpenModal : undefined}
|
||||
className={clsx('w-full h-full', { 'cursor-zoom-in': clickable, 'cursor-default': !clickable })}
|
||||
className={clsx('h-full w-full', { 'cursor-zoom-in': clickable, 'cursor-default': !clickable })}
|
||||
>
|
||||
<ChatUploadPreview attachment={attachment} />
|
||||
</button>
|
||||
|
@ -53,10 +53,10 @@ const RemoveButton: React.FC<IRemoveButton> = ({ onClick }) => {
|
|||
<button
|
||||
type='button'
|
||||
onClick={onClick}
|
||||
className='bg-secondary-500 w-5 h-5 p-1 rounded-full flex items-center justify-center'
|
||||
className='flex h-5 w-5 items-center justify-center rounded-full bg-secondary-500 p-1'
|
||||
>
|
||||
<Icon
|
||||
className='w-4 h-4 text-white'
|
||||
className='h-4 w-4 text-white'
|
||||
src={require('@tabler/icons/x.svg')}
|
||||
/>
|
||||
</button>
|
||||
|
|
|
@ -31,9 +31,9 @@ const ChatPaneHeader = (props: IChatPaneHeader) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<HStack {...rest} alignItems='center' justifyContent='between' className='rounded-t-xl h-16 py-3 px-4'>
|
||||
<HStack {...rest} alignItems='center' justifyContent='between' className='h-16 rounded-t-xl py-3 px-4'>
|
||||
<ButtonComp
|
||||
className='flex-grow flex items-center flex-row space-x-1 h-16'
|
||||
className='flex h-16 grow flex-row items-center space-x-1'
|
||||
data-testid='title'
|
||||
{...buttonProps}
|
||||
>
|
||||
|
@ -47,7 +47,7 @@ const ChatPaneHeader = (props: IChatPaneHeader) => {
|
|||
({unreadCount})
|
||||
</Text>
|
||||
|
||||
<div className='bg-accent-300 w-2.5 h-2.5 rounded-full' />
|
||||
<div className='h-2.5 w-2.5 rounded-full bg-accent-300' />
|
||||
</HStack>
|
||||
)}
|
||||
</ButtonComp>
|
||||
|
|
|
@ -107,7 +107,7 @@ const ChatSettings = () => {
|
|||
}
|
||||
/>
|
||||
|
||||
<Stack space={4} className='w-5/6 mx-auto'>
|
||||
<Stack space={4} className='mx-auto w-5/6'>
|
||||
<HStack alignItems='center' space={3}>
|
||||
<Avatar src={chat.account.avatar_static} size={50} />
|
||||
<Stack>
|
||||
|
@ -135,14 +135,14 @@ const ChatSettings = () => {
|
|||
)}
|
||||
|
||||
<Stack space={5}>
|
||||
<button onClick={isBlocking ? handleUnblockUser : handleBlockUser} className='w-full flex items-center space-x-2 font-bold text-sm text-primary-600 dark:text-accent-blue'>
|
||||
<Icon src={require('@tabler/icons/ban.svg')} className='w-5 h-5' />
|
||||
<button onClick={isBlocking ? handleUnblockUser : handleBlockUser} className='flex w-full items-center space-x-2 text-sm font-bold text-primary-600 dark:text-accent-blue'>
|
||||
<Icon src={require('@tabler/icons/ban.svg')} className='h-5 w-5' />
|
||||
<span>{intl.formatMessage(isBlocking ? messages.unblockUser : messages.blockUser, { acct: chat.account.acct })}</span>
|
||||
</button>
|
||||
|
||||
{features.chatsDelete && (
|
||||
<button onClick={handleLeaveChat} className='w-full flex items-center space-x-2 font-bold text-sm text-danger-600'>
|
||||
<Icon src={require('@tabler/icons/logout.svg')} className='w-5 h-5' />
|
||||
<button onClick={handleLeaveChat} className='flex w-full items-center space-x-2 text-sm font-bold text-danger-600'>
|
||||
<Icon src={require('@tabler/icons/logout.svg')} className='h-5 w-5' />
|
||||
<span>{intl.formatMessage(messages.leaveChat)}</span>
|
||||
</button>
|
||||
)}
|
||||
|
|
|
@ -87,7 +87,7 @@ const ChatWindow = () => {
|
|||
|
||||
<Stack alignItems='start'>
|
||||
<LinkWrapper enabled={isOpen} to={`/@${chat.account.acct}`}>
|
||||
<div className='flex items-center space-x-1 flex-grow'>
|
||||
<div className='flex grow items-center space-x-1'>
|
||||
<Text size='sm' weight='bold' truncate>{chat.account.display_name || `@${chat.account.acct}`}</Text>
|
||||
{chat.account.verified && <VerificationBadge />}
|
||||
</div>
|
||||
|
@ -113,7 +113,7 @@ const ChatWindow = () => {
|
|||
onToggle={toggleChatPane}
|
||||
/>
|
||||
|
||||
<Stack className='overflow-hidden flex-grow h-full' space={2}>
|
||||
<Stack className='h-full grow overflow-hidden' space={2}>
|
||||
<Chat chat={chat} inputRef={inputRef} />
|
||||
</Stack>
|
||||
</>
|
||||
|
|
|
@ -158,7 +158,7 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
|||
|
||||
return (
|
||||
<Stack className={classNames('overflow-hidden flex flex-grow', className)} onMouseOver={handleMouseOver}>
|
||||
<div className='flex-grow h-full overflow-hidden flex justify-center'>
|
||||
<div className='flex h-full grow justify-center overflow-hidden'>
|
||||
<ChatMessageList chat={chat} />
|
||||
</div>
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ const DurationSelector = ({ onDurationChange }: IDurationSelector) => {
|
|||
}, [value]);
|
||||
|
||||
return (
|
||||
<div className='grid grid-cols-1 gap-y-2 gap-x-2 sm:grid-cols-3'>
|
||||
<div className='grid grid-cols-1 gap-2 sm:grid-cols-3'>
|
||||
<div className='sm:col-span-1'>
|
||||
<Select
|
||||
value={days}
|
||||
|
|
|
@ -79,7 +79,7 @@ const Option: React.FC<IOption> = ({
|
|||
</div>
|
||||
|
||||
<AutosuggestInput
|
||||
className='rounded-md dark:!bg-transparent !bg-transparent'
|
||||
className='rounded-md !bg-transparent dark:!bg-transparent'
|
||||
placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}
|
||||
maxLength={maxChars}
|
||||
value={title}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue