Merge branch 'fix-classnames' into 'main'
Fix classnames warnings Closes #1761 See merge request soapbox-pub/soapbox!3210
This commit is contained in:
commit
5725cc4a80
|
@ -21,6 +21,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<noscript>To use this website, please enable JavaScript.</noscript>
|
<noscript class="text-center">To use this website, please enable JavaScript.</noscript>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -25,13 +25,12 @@ const AutosuggestEmoji: React.FC<IAutosuggestEmoji> = ({ emoji }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='autosuggest-emoji' data-testid='emoji'>
|
<div className='flex flex-row items-center justify-start text-[14px] leading-[18px]' data-testid='emoji'>
|
||||||
<img
|
<img
|
||||||
className='emojione'
|
className='emojione mr-2 block size-4'
|
||||||
src={url}
|
src={url}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{emoji.colons}
|
{emoji.colons}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -235,7 +235,7 @@ export default class AutosuggestInput extends PureComponent<IAutosuggestInput> {
|
||||||
return menu.map((item, i) => (
|
return menu.map((item, i) => (
|
||||||
<a // eslint-disable-line jsx-a11y/anchor-is-valid
|
<a // eslint-disable-line jsx-a11y/anchor-is-valid
|
||||||
className={clsx('flex cursor-pointer items-center space-x-2 px-4 py-2.5 text-sm text-gray-700 hover:bg-gray-100 focus:bg-gray-100 dark:text-gray-500 dark:hover:bg-gray-800 dark:focus:bg-primary-800', { selected: suggestions.size - selectedSuggestion === i })}
|
className={clsx('flex cursor-pointer items-center space-x-2 px-4 py-2.5 text-sm text-gray-700 hover:bg-gray-100 focus:bg-gray-100 dark:text-gray-500 dark:hover:bg-gray-800 dark:focus:bg-primary-800', { selected: suggestions.size - selectedSuggestion === i })}
|
||||||
href='#'
|
href='/'
|
||||||
role='button'
|
role='button'
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onMouseDown={this.handleMenuItemClick(item)}
|
onMouseDown={this.handleMenuItemClick(item)}
|
||||||
|
|
|
@ -32,7 +32,7 @@ const DisplayNameInline: React.FC<IDisplayName> = ({ account, withSuffix = true
|
||||||
);
|
);
|
||||||
|
|
||||||
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
||||||
const suffix = (<span className='display-name'>@{getAcct(account, displayFqn)}</span>);
|
const suffix = (<span className='relative block max-w-full truncate'>@{getAcct(account, displayFqn)}</span>);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex max-w-80 flex-col items-center justify-center text-center sm:flex-row sm:gap-2'>
|
<div className='flex max-w-80 flex-col items-center justify-center text-center sm:flex-row sm:gap-2'>
|
||||||
|
|
|
@ -33,10 +33,10 @@ const DisplayName: React.FC<IDisplayName> = ({ account, children, withSuffix = t
|
||||||
</HStack>
|
</HStack>
|
||||||
);
|
);
|
||||||
|
|
||||||
const suffix = (<span className='display-name__account'>@{getAcct(account, displayFqn)}</span>); // eslint-disable-line formatjs/no-literal-string-in-jsx
|
const suffix = (<span className='relative text-[14px] font-semibold'>@{getAcct(account, displayFqn)}</span>); // eslint-disable-line formatjs/no-literal-string-in-jsx
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className='display-name' data-testid='display-name'>
|
<span className='relative block max-w-full truncate' data-testid='display-name'>
|
||||||
<HoverRefWrapper accountId={account.id} inline>
|
<HoverRefWrapper accountId={account.id} inline>
|
||||||
{displayName}
|
{displayName}
|
||||||
</HoverRefWrapper>
|
</HoverRefWrapper>
|
||||||
|
|
|
@ -42,10 +42,11 @@ const ExtendedVideoPlayer: React.FC<IExtendedVideoPlayer> = ({ src, alt, time, c
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='extended-video-player'>
|
<div className='flex size-full items-center justify-center'>
|
||||||
<video
|
<video
|
||||||
ref={video}
|
ref={video}
|
||||||
src={src}
|
src={src}
|
||||||
|
className='max-h-[80%] max-w-full'
|
||||||
autoPlay
|
autoPlay
|
||||||
role='button'
|
role='button'
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
|
|
|
@ -24,7 +24,7 @@ const ForkAwesomeIcon: React.FC<IForkAwesomeIcon> = ({ id, className, fixedWidth
|
||||||
<i
|
<i
|
||||||
role='img'
|
role='img'
|
||||||
// alt={alt}
|
// alt={alt}
|
||||||
className={clsx('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })}
|
className={clsx('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })} // eslint-disable-line tailwindcss/no-custom-classname
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -47,7 +47,7 @@ export const HoverRefWrapper: React.FC<IHoverRefWrapper> = ({ accountId, childre
|
||||||
return (
|
return (
|
||||||
<Elem
|
<Elem
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={clsx('hover-ref-wrapper', className)}
|
className={clsx(className)}
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
@ -45,7 +44,7 @@ export const HoverStatusWrapper: React.FC<IHoverStatusWrapper> = ({ statusId, ch
|
||||||
return (
|
return (
|
||||||
<Elem
|
<Elem
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={clsx('hover-status-wrapper', className)}
|
className={className}
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
|
|
|
@ -65,9 +65,9 @@ const IconButton: React.FC<IIconButton> = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const classes = clsx(className, 'icon-button', {
|
const classes = clsx(className, 'inline-flex cursor-pointer items-center border-0 bg-transparent p-0 text-black opacity-40 transition-opacity duration-100 ease-in hover:opacity-60 hover:transition-colors hover:duration-200 focus:opacity-60 focus:outline-none focus:transition-colors focus:duration-200 dark:text-white', {
|
||||||
active,
|
'opacity-60 outline-none transition-colors duration-200': active,
|
||||||
disabled,
|
'opacity-20 cursor-default': disabled,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -88,10 +88,10 @@ const IconButton: React.FC<IIconButton> = ({
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
type='button'
|
type='button'
|
||||||
>
|
>
|
||||||
<div>
|
<div className='flex items-center justify-center'>
|
||||||
<Icon className={iconClassName} src={src} aria-hidden='true' />
|
<Icon className={iconClassName} src={src} aria-hidden='true' />
|
||||||
</div>
|
</div>
|
||||||
{text && <span className='icon-button__text'>{text}</span>}
|
{text && <span className='pl-0.5'>{text}</span>}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import dotsIcon from '@tabler/icons/outline/dots.svg';
|
import dotsIcon from '@tabler/icons/outline/dots.svg';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import Icon from 'soapbox/components/icon.tsx';
|
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
|
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
|
||||||
|
@ -19,8 +19,8 @@ const LoadGap: React.FC<ILoadGap> = ({ disabled, maxId, onClick }) => {
|
||||||
const handleClick = () => onClick(maxId);
|
const handleClick = () => onClick(maxId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className='load-more load-gap' disabled={disabled} onClick={handleClick} aria-label={intl.formatMessage(messages.load_more)}>
|
<button className='m-0 box-border block w-full border-0 bg-transparent p-4 text-gray-900' disabled={disabled} onClick={handleClick} aria-label={intl.formatMessage(messages.load_more)}>
|
||||||
<Icon src={dotsIcon} />
|
<SvgIcon className='mx-auto' src={dotsIcon} />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { locationSearch } from 'soapbox/actions/events.ts';
|
import { locationSearch } from 'soapbox/actions/events.ts';
|
||||||
import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest-input.tsx';
|
import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest-input.tsx';
|
||||||
import Icon from 'soapbox/components/icon.tsx';
|
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
|
||||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||||
|
|
||||||
import AutosuggestLocation from './autosuggest-location.tsx';
|
import AutosuggestLocation from './autosuggest-location.tsx';
|
||||||
|
@ -87,7 +87,7 @@ const LocationSearch: React.FC<ILocationSearch> = ({ onSelected }) => {
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='search'>
|
<div className='relative'>
|
||||||
<AutosuggestInput
|
<AutosuggestInput
|
||||||
className='rounded-full'
|
className='rounded-full'
|
||||||
placeholder={intl.formatMessage(messages.placeholder)}
|
placeholder={intl.formatMessage(messages.placeholder)}
|
||||||
|
@ -101,9 +101,9 @@ const LocationSearch: React.FC<ILocationSearch> = ({ onSelected }) => {
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
renderSuggestion={AutosuggestLocation}
|
renderSuggestion={AutosuggestLocation}
|
||||||
/>
|
/>
|
||||||
<div role='button' tabIndex={0} className='search__icon' onClick={handleClear}>
|
<div role='button' tabIndex={0} className='focus:!outline-0' onClick={handleClear}>
|
||||||
<Icon src={searchIcon} className={clsx('svg-icon--search', { active: isEmpty() })} />
|
<SvgIcon src={searchIcon} className={clsx('pointer-events-none absolute right-4 top-1/2 z-[2] inline-block size-[18px] -translate-y-1/2 cursor-default text-gray-400 opacity-0 rtl:left-4 rtl:right-auto', { 'opacity-100': isEmpty() })} />
|
||||||
<Icon src={backspaceIcon} className={clsx('svg-icon--backspace', { active: !isEmpty() })} aria-label={intl.formatMessage(messages.placeholder)} />
|
<SvgIcon src={backspaceIcon} className={clsx('pointer-events-none absolute right-4 top-1/2 z-[2] inline-block size-[22px] -translate-y-1/2 cursor-pointer text-gray-400 opacity-0 rtl:left-4 rtl:right-auto', { 'pointer-events-auto opacity-100': !isEmpty() })} aria-label={intl.formatMessage(messages.placeholder)} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,8 +8,8 @@ import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
import Blurhash from 'soapbox/components/blurhash.tsx';
|
import Blurhash from 'soapbox/components/blurhash.tsx';
|
||||||
import HStack from 'soapbox/components/ui/hstack.tsx';
|
import HStack from 'soapbox/components/ui/hstack.tsx';
|
||||||
import Icon from 'soapbox/components/ui/icon.tsx';
|
|
||||||
import Stack from 'soapbox/components/ui/stack.tsx';
|
import Stack from 'soapbox/components/ui/stack.tsx';
|
||||||
|
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
|
||||||
import Text from 'soapbox/components/ui/text.tsx';
|
import Text from 'soapbox/components/ui/text.tsx';
|
||||||
import { normalizeAttachment } from 'soapbox/normalizers/index.ts';
|
import { normalizeAttachment } from 'soapbox/normalizers/index.ts';
|
||||||
import { addAutoPlay } from 'soapbox/utils/media.ts';
|
import { addAutoPlay } from 'soapbox/utils/media.ts';
|
||||||
|
@ -96,7 +96,7 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={setRef}
|
ref={setRef}
|
||||||
className='status-card__image status-card-video'
|
className='relative w-full flex-none overflow-hidden'
|
||||||
dangerouslySetInnerHTML={content}
|
dangerouslySetInnerHTML={content}
|
||||||
style={{ height }}
|
style={{ height }}
|
||||||
/>
|
/>
|
||||||
|
@ -113,7 +113,7 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||||
|
|
||||||
const interactive = card.type !== 'link';
|
const interactive = card.type !== 'link';
|
||||||
horizontal = typeof horizontal === 'boolean' ? horizontal : interactive || embedded;
|
horizontal = typeof horizontal === 'boolean' ? horizontal : interactive || embedded;
|
||||||
const className = clsx('status-card', { horizontal, compact, interactive }, `status-card--${card.type}`);
|
const className = clsx('flex overflow-hidden rounded-lg border border-solid border-gray-200 text-sm text-gray-800 no-underline dark:border-gray-800 dark:text-gray-200', { '!block': horizontal, 'border-gray-200 dark:border-gray-800': compact, interactive, 'flex flex-col md:flex-row': card.type === 'link' });
|
||||||
const ratio = getRatio(card);
|
const ratio = getRatio(card);
|
||||||
const height = (compact && !embedded) ? (width / (16 / 9)) : (width / ratio);
|
const height = (compact && !embedded) ? (width / (16 / 9)) : (width / ratio);
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||||
)}
|
)}
|
||||||
<HStack space={1} alignItems='center'>
|
<HStack space={1} alignItems='center'>
|
||||||
<Text tag='span' theme='muted'>
|
<Text tag='span' theme='muted'>
|
||||||
<Icon src={linkIcon} />
|
<SvgIcon src={linkIcon} />
|
||||||
</Text>
|
</Text>
|
||||||
<Text tag='span' theme='muted' size='sm' direction={direction}>
|
<Text tag='span' theme='muted' size='sm' direction={direction}>
|
||||||
{card.provider_name}
|
{card.provider_name}
|
||||||
|
@ -167,7 +167,7 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||||
width: horizontal ? width : undefined,
|
width: horizontal ? width : undefined,
|
||||||
height: horizontal ? height : undefined,
|
height: horizontal ? height : undefined,
|
||||||
}}
|
}}
|
||||||
className='status-card__image-image'
|
className='block size-full bg-cover bg-center object-cover'
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
embed = (
|
embed = (
|
||||||
<div className='status-card__image'>
|
<div className='relative w-full flex-none overflow-hidden' style={{ flex: '0 0 40%' }}>
|
||||||
{canvas}
|
{canvas}
|
||||||
{thumbnail}
|
{thumbnail}
|
||||||
|
|
||||||
|
@ -190,9 +190,9 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||||
<div className='flex items-center justify-center rounded-full bg-gray-500/90 px-4 py-3 shadow-md dark:bg-gray-700/90'>
|
<div className='flex items-center justify-center rounded-full bg-gray-500/90 px-4 py-3 shadow-md dark:bg-gray-700/90'>
|
||||||
<HStack space={3} alignItems='center'>
|
<HStack space={3} alignItems='center'>
|
||||||
<button onClick={handleEmbedClick} className='appearance-none text-gray-700 hover:text-gray-900 dark:text-gray-500 dark:hover:text-gray-100'>
|
<button onClick={handleEmbedClick} className='appearance-none text-gray-700 hover:text-gray-900 dark:text-gray-500 dark:hover:text-gray-100'>
|
||||||
<Icon
|
<SvgIcon
|
||||||
src={iconVariant}
|
src={iconVariant}
|
||||||
className='size-6 text-inherit'
|
className=' size-6 text-inherit'
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||||
rel='noopener'
|
rel='noopener'
|
||||||
className='text-gray-700 hover:text-gray-900 dark:text-gray-500 dark:hover:text-gray-100'
|
className='text-gray-700 hover:text-gray-900 dark:text-gray-500 dark:hover:text-gray-100'
|
||||||
>
|
>
|
||||||
<Icon
|
<SvgIcon
|
||||||
src={externalLinkIcon}
|
src={externalLinkIcon}
|
||||||
className='size-6 text-inherit'
|
className='size-6 text-inherit'
|
||||||
/>
|
/>
|
||||||
|
@ -226,7 +226,7 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||||
} else if (card.image) {
|
} else if (card.image) {
|
||||||
embed = (
|
embed = (
|
||||||
<div className={clsx(
|
<div className={clsx(
|
||||||
'status-card__image',
|
'relative overflow-hidden',
|
||||||
'w-full flex-none rounded-l md:size-auto md:flex-auto',
|
'w-full flex-none rounded-l md:size-auto md:flex-auto',
|
||||||
{
|
{
|
||||||
'h-auto': horizontal,
|
'h-auto': horizontal,
|
||||||
|
@ -243,7 +243,7 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
href={card.url}
|
href={card.url}
|
||||||
className={className}
|
className={clsx(className, 'cursor-pointer hover:bg-gray-100 hover:no-underline dark:hover:bg-primary-800/30')}
|
||||||
target='_blank'
|
target='_blank'
|
||||||
rel='noopener'
|
rel='noopener'
|
||||||
ref={setRef}
|
ref={setRef}
|
||||||
|
|
|
@ -172,9 +172,8 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div
|
<button
|
||||||
className='fixed inset-0 bg-gray-500/90 black:bg-gray-900/90 dark:bg-gray-700/90'
|
className='fixed inset-0 bg-gray-500/90 black:bg-gray-900/90 dark:bg-gray-700/90'
|
||||||
role='button'
|
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -212,10 +212,12 @@ const StatusList: React.FC<IStatusList> = ({
|
||||||
|
|
||||||
if (isPartial) {
|
if (isPartial) {
|
||||||
return (
|
return (
|
||||||
<div className='regeneration-indicator'>
|
<div className='flex flex-1 cursor-default items-center justify-center rounded-lg p-5 text-center text-[16px] font-medium text-gray-900 sm:rounded-none'>
|
||||||
<div>
|
<div className='w-full bg-transparent pt-0'>
|
||||||
<div className='regeneration-indicator__label'>
|
<div>
|
||||||
<FormattedMessage id='regeneration_indicator.label' tagName='strong' defaultMessage='Loading…' />
|
<strong className='mb-2.5 block text-gray-900'>
|
||||||
|
<FormattedMessage id='regeneration_indicator.label' defaultMessage='Loading…' />
|
||||||
|
</strong>
|
||||||
<FormattedMessage id='regeneration_indicator.sublabel' defaultMessage='Your home feed is being prepared!' />
|
<FormattedMessage id='regeneration_indicator.sublabel' defaultMessage='Your home feed is being prepared!' />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -41,15 +41,15 @@ const StatusMedia: React.FC<IStatusMedia> = ({
|
||||||
let media: JSX.Element | null = null;
|
let media: JSX.Element | null = null;
|
||||||
|
|
||||||
const renderLoadingMediaGallery = (): JSX.Element => {
|
const renderLoadingMediaGallery = (): JSX.Element => {
|
||||||
return <div className='media_gallery' style={{ height: '285px' }} />;
|
return <div className='relative isolate box-border h-auto w-full overflow-hidden rounded-lg' style={{ height: '285px' }} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderLoadingVideoPlayer = (): JSX.Element => {
|
const renderLoadingVideoPlayer = (): JSX.Element => {
|
||||||
return <div className='media-spoiler-video' style={{ height: '285px' }} />;
|
return <div className='relative mt-2 block cursor-pointer border-0 bg-cover bg-center bg-no-repeat' style={{ height: '285px' }} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderLoadingAudioPlayer = (): JSX.Element => {
|
const renderLoadingAudioPlayer = (): JSX.Element => {
|
||||||
return <div className='media-spoiler-audio' style={{ height: '285px' }} />;
|
return <div className='relative mt-2 block cursor-pointer border-0 bg-cover bg-center bg-no-repeat' style={{ height: '285px' }} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const openMedia = (media: ImmutableList<Attachment>, index: number) => {
|
const openMedia = (media: ImmutableList<Attachment>, index: number) => {
|
||||||
|
|
|
@ -38,7 +38,7 @@ const StatusReplyMentions: React.FC<IStatusReplyMentions> = ({ status, hoverable
|
||||||
// Rare, but it can happen.
|
// Rare, but it can happen.
|
||||||
if (to.size === 0) {
|
if (to.size === 0) {
|
||||||
return (
|
return (
|
||||||
<div className='reply-mentions'>
|
<div className='mb-1 text-sm text-gray-700 dark:text-gray-600'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='reply_mentions.reply_empty'
|
id='reply_mentions.reply_empty'
|
||||||
defaultMessage='Replying to post'
|
defaultMessage='Replying to post'
|
||||||
|
@ -53,7 +53,7 @@ const StatusReplyMentions: React.FC<IStatusReplyMentions> = ({ status, hoverable
|
||||||
<Link
|
<Link
|
||||||
key={account.id}
|
key={account.id}
|
||||||
to={`/@${account.acct}`}
|
to={`/@${account.acct}`}
|
||||||
className='reply-mentions__account max-w-[200px] truncate align-bottom'
|
className='inline-block max-w-[200px] truncate align-bottom text-primary-600 no-underline hover:text-primary-700 hover:underline dark:text-accent-blue dark:hover:text-accent-blue' style={{ direction: 'ltr' }}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
> {/* eslint-disable-line formatjs/no-literal-string-in-jsx */}
|
> {/* eslint-disable-line formatjs/no-literal-string-in-jsx */}
|
||||||
@{shortenNostr(account.username)}
|
@{shortenNostr(account.username)}
|
||||||
|
@ -80,7 +80,7 @@ const StatusReplyMentions: React.FC<IStatusReplyMentions> = ({ status, hoverable
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='reply-mentions'>
|
<div className='mb-1 text-sm text-gray-700 dark:text-gray-600'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='reply_mentions.reply.hoverable'
|
id='reply_mentions.reply.hoverable'
|
||||||
defaultMessage='<hover>Replying to</hover> {accounts}'
|
defaultMessage='<hover>Replying to</hover> {accounts}'
|
||||||
|
|
|
@ -340,7 +340,7 @@ const Status: React.FC<IStatus> = (props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={minHandlers}>
|
<HotKeys handlers={minHandlers}>
|
||||||
<div className={clsx('status__wrapper text-center', { focusable })} tabIndex={focusable ? 0 : undefined} ref={node}>
|
<div className={clsx('status--wrapper text-center', { focusable })} tabIndex={focusable ? 0 : undefined} ref={node}>
|
||||||
{/* eslint-disable formatjs/no-literal-string-in-jsx */}
|
{/* eslint-disable formatjs/no-literal-string-in-jsx */}
|
||||||
<Text theme='muted'>
|
<Text theme='muted'>
|
||||||
<FormattedMessage id='status.filtered' defaultMessage='Filtered' />: {status.filtered.join(', ')}.
|
<FormattedMessage id='status.filtered' defaultMessage='Filtered' />: {status.filtered.join(', ')}.
|
||||||
|
@ -368,7 +368,7 @@ const Status: React.FC<IStatus> = (props) => {
|
||||||
if (actualStatus.quote) {
|
if (actualStatus.quote) {
|
||||||
if (actualStatus.pleroma.get('quote_visible', true) === false) {
|
if (actualStatus.pleroma.get('quote_visible', true) === false) {
|
||||||
quote = (
|
quote = (
|
||||||
<div className='quoted-status-tombstone'>
|
<div>
|
||||||
<p><FormattedMessage id='statuses.quote_tombstone' defaultMessage='Post is unavailable.' /></p>
|
<p><FormattedMessage id='statuses.quote_tombstone' defaultMessage='Post is unavailable.' /></p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -408,6 +408,7 @@ const Status: React.FC<IStatus> = (props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers} data-testid='status'>
|
<HotKeys handlers={handlers} data-testid='status'>
|
||||||
|
{/* eslint-disable-next-line jsx-a11y/interactive-supports-focus */}
|
||||||
<div
|
<div
|
||||||
className={clsx('status cursor-pointer', { focusable })}
|
className={clsx('status cursor-pointer', { focusable })}
|
||||||
tabIndex={focusable && !muted ? 0 : undefined}
|
tabIndex={focusable && !muted ? 0 : undefined}
|
||||||
|
@ -419,11 +420,8 @@ const Status: React.FC<IStatus> = (props) => {
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
variant={variant}
|
variant={variant}
|
||||||
className={clsx('status__wrapper space-y-4', `status-${actualStatus.visibility}`, {
|
className={clsx('status--wrapper space-y-4', {
|
||||||
'py-6 sm:p-5': variant === 'rounded',
|
'py-6 sm:p-5': variant === 'rounded', muted, read: unread === false,
|
||||||
'status-reply': !!status.in_reply_to_id,
|
|
||||||
muted,
|
|
||||||
read: unread === false,
|
|
||||||
})}
|
})}
|
||||||
data-id={status.id}
|
data-id={status.id}
|
||||||
>
|
>
|
||||||
|
@ -443,7 +441,7 @@ const Status: React.FC<IStatus> = (props) => {
|
||||||
avatarSize={avatarSize}
|
avatarSize={avatarSize}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='status__content-wrapper'>
|
<div className='status--content-wrapper'>
|
||||||
<StatusReplyMentions status={actualStatus} hoverable={hoverable} />
|
<StatusReplyMentions status={actualStatus} hoverable={hoverable} />
|
||||||
|
|
||||||
<Stack
|
<Stack
|
||||||
|
|
|
@ -32,7 +32,7 @@ const ThumbNavigationLink: React.FC<IThumbNavigationLink> = ({ count, countMax,
|
||||||
const icon = (active && activeSrc) || src;
|
const icon = (active && activeSrc) || src;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavLink to={to} exact={exact} className='thumb-navigation__link'>
|
<NavLink to={to} exact={exact} className='flex flex-1 flex-col items-center space-y-1 px-2 py-2.5 text-lg text-gray-600'>
|
||||||
{count !== undefined ? (
|
{count !== undefined ? (
|
||||||
<IconWithCounter
|
<IconWithCounter
|
||||||
src={icon}
|
src={icon}
|
||||||
|
|
|
@ -57,7 +57,14 @@ const ThumbNavigation: React.FC = (): JSX.Element => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='thumb-navigation'>
|
<div
|
||||||
|
className='hide-scrollbar fixed inset-x-0 bottom-0 z-50 flex w-full border-t border-solid border-gray-200 bg-white/90 shadow-2xl backdrop-blur-md black:bg-black/90 dark:border-gray-800 dark:bg-primary-900/90 lg:hidden' style={{
|
||||||
|
paddingBottom: 'env(safe-area-inset-bottom)', // iOS PWA
|
||||||
|
overflowX: 'auto',
|
||||||
|
scrollbarWidth: 'thin',
|
||||||
|
scrollbarColor: '#fff transparent',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ThumbNavigationLink
|
<ThumbNavigationLink
|
||||||
src={homeIcon}
|
src={homeIcon}
|
||||||
activeSrc={homeFilledIcon}
|
activeSrc={homeFilledIcon}
|
||||||
|
|
|
@ -20,7 +20,7 @@ const Tombstone: React.FC<ITombstone> = ({ id, onMoveUp, onMoveDown }) => {
|
||||||
<HotKeys handlers={handlers}>
|
<HotKeys handlers={handlers}>
|
||||||
<div className='h-16'>
|
<div className='h-16'>
|
||||||
<div
|
<div
|
||||||
className='focusable flex h-[42px] items-center justify-center rounded-lg border-2 border-gray-200 text-center dark:border-gray-800'
|
className='flex h-[42px] items-center justify-center rounded-lg border-2 border-gray-200 text-center focus-within:outline-none focus-within:ring-2 focus-within:ring-primary-300 focus:outline-none focus:ring-2 focus:ring-primary-300 dark:border-gray-800'
|
||||||
>
|
>
|
||||||
<Text theme='muted'>
|
<Text theme='muted'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
|
|
@ -54,13 +54,17 @@ const FormGroup: React.FC<IFormGroup> = (props) => {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{hasError && (
|
{hasError && (
|
||||||
<div>
|
<div className='relative'>
|
||||||
|
<div className='pointer-events-none absolute bottom-full left-2.5 -ml-px size-0 border-[6px] border-solid border-transparent' style={{ borderBottomColor: 'rgba(254, 202, 202, var(--tw-bg-opacity))', '--tw-bg-opacity': '1' } as React.CSSProperties} />
|
||||||
|
|
||||||
<p
|
<p
|
||||||
data-testid='form-group-error'
|
data-testid='form-group-error'
|
||||||
className='form-error relative mt-0.5 inline-block rounded-md bg-danger-200 px-2 py-1 text-xs text-danger-900'
|
className='relative mt-0.5 inline-block rounded-md bg-danger-200 px-2 py-1 text-xs text-danger-900'
|
||||||
>
|
>
|
||||||
{errors.join(', ')}
|
{errors.join(', ')}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div className='pointer-events-none absolute bottom-full left-2.5 size-0 border-[6px] border-transparent' />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -98,12 +102,18 @@ const FormGroup: React.FC<IFormGroup> = (props) => {
|
||||||
{inputChildren.filter((_, i) => i !== 0)}
|
{inputChildren.filter((_, i) => i !== 0)}
|
||||||
|
|
||||||
{hasError && (
|
{hasError && (
|
||||||
<p
|
<div className='relative'>
|
||||||
data-testid='form-group-error'
|
<div className='pointer-events-none absolute bottom-full left-2.5 -ml-px size-0 border-[6px] border-solid border-transparent' style={{ borderBottomColor: 'rgba(254, 202, 202, var(--tw-bg-opacity))', '--tw-bg-opacity': '1' } as React.CSSProperties} />
|
||||||
className='form-error relative mt-0.5 inline-block rounded-md bg-danger-200 px-2 py-1 text-xs text-danger-900'
|
|
||||||
>
|
<p
|
||||||
{errors.join(', ')}
|
data-testid='form-group-error'
|
||||||
</p>
|
className='relative mt-0.5 inline-block rounded-md bg-danger-200 px-2 py-1 text-xs text-danger-900'
|
||||||
|
>
|
||||||
|
{errors.join(', ')}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className='pointer-events-none absolute bottom-full left-2.5 size-0 border-[6px] border-transparent' />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -27,7 +27,7 @@ const MenuList: React.FC<IMenuList> = (props) => {
|
||||||
<MenuItems
|
<MenuItems
|
||||||
onKeyDown={(event) => event.nativeEvent.stopImmediatePropagation()}
|
onKeyDown={(event) => event.nativeEvent.stopImmediatePropagation()}
|
||||||
className={
|
className={
|
||||||
clsx(className, 'shadow-menu rounded-lg bg-white py-1 black:bg-black dark:bg-primary-900')
|
clsx(className, 'rounded-lg bg-white py-1 black:bg-black dark:bg-primary-900')
|
||||||
}
|
}
|
||||||
{...filteredProps}
|
{...filteredProps}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -24,7 +24,7 @@ const VerificationBadge: React.FC<IVerificationBadge> = ({ className }) => {
|
||||||
const Element = icon.endsWith('.svg') ? Icon : 'img';
|
const Element = icon.endsWith('.svg') ? Icon : 'img';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className='verified-icon' data-testid='verified-badge'>
|
<span data-testid='verified-badge'>
|
||||||
<Element className={clsx('w-4 text-accent-500', className)} src={icon} alt={intl.formatMessage(messages.verified)} />
|
<Element className={clsx('w-4 text-accent-500', className)} src={icon} alt={intl.formatMessage(messages.verified)} />
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
|
@ -107,7 +107,7 @@ const AccountGallery = () => {
|
||||||
if (isUnavailable) {
|
if (isUnavailable) {
|
||||||
return (
|
return (
|
||||||
<Column>
|
<Column>
|
||||||
<div className='empty-column-indicator'>
|
<div className='flex min-h-[160px] flex-1 items-center justify-center rounded-lg bg-primary-50 p-10 text-center text-gray-900 dark:bg-gray-700 dark:text-gray-300'>
|
||||||
<FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />
|
<FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />
|
||||||
</div>
|
</div>
|
||||||
</Column>
|
</Column>
|
||||||
|
@ -128,7 +128,7 @@ const AccountGallery = () => {
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{!isLoading && attachments.size === 0 && (
|
{!isLoading && attachments.size === 0 && (
|
||||||
<div className='empty-column-indicator col-span-2 sm:col-span-3'>
|
<div className='col-span-2 flex min-h-[160px] flex-1 items-center justify-center rounded-lg bg-primary-50 p-10 text-center text-gray-900 dark:bg-gray-700 dark:text-gray-300 sm:col-span-3'>
|
||||||
<FormattedMessage id='account_gallery.none' defaultMessage='No media to show.' />
|
<FormattedMessage id='account_gallery.none' defaultMessage='No media to show.' />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -137,7 +137,7 @@ const AccountGallery = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isLoading && attachments.size === 0 && (
|
{isLoading && attachments.size === 0 && (
|
||||||
<div className='slist__append'>
|
<div className='relative flex flex-1 p-[30px_15px]'>
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -3,8 +3,8 @@ import clsx from 'clsx';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { fetchAliasesSuggestions, clearAliasesSuggestions, changeAliasesSuggestions } from 'soapbox/actions/aliases.ts';
|
import { fetchAliasesSuggestions, clearAliasesSuggestions, changeAliasesSuggestions } from 'soapbox/actions/aliases.ts';
|
||||||
import Icon from 'soapbox/components/icon.tsx';
|
|
||||||
import Button from 'soapbox/components/ui/button.tsx';
|
import Button from 'soapbox/components/ui/button.tsx';
|
||||||
|
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
|
||||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ const Search: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div role='button' tabIndex={hasValue ? 0 : -1} className='search__icon' onClick={handleClear}>
|
<div role='button' tabIndex={hasValue ? 0 : -1} className='search__icon' onClick={handleClear}>
|
||||||
<Icon src={backspaceIcon} aria-label={intl.formatMessage(messages.search)} className={clsx('svg-icon--backspace', { active: hasValue })} />
|
<SvgIcon src={backspaceIcon} aria-label={intl.formatMessage(messages.search)} className={clsx('pointer-events-none absolute right-4 top-1/2 z-20 inline-block size-4.5 -translate-y-1/2 cursor-default text-[16px] text-gray-400 opacity-0 rtl:left-4 rtl:right-auto', { 'pointer-events-auto opacity-100': hasValue })} />
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<Button onClick={handleSubmit}>{intl.formatMessage(messages.searchTitle)}</Button>
|
<Button onClick={handleSubmit}>{intl.formatMessage(messages.searchTitle)}</Button>
|
||||||
|
|
|
@ -54,18 +54,20 @@ const Aliases = () => {
|
||||||
const emptyMessage = <FormattedMessage id='empty_column.aliases' defaultMessage="You haven't created any account alias yet." />;
|
const emptyMessage = <FormattedMessage id='empty_column.aliases' defaultMessage="You haven't created any account alias yet." />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column className='aliases-settings-panel' label={intl.formatMessage(messages.heading)}>
|
<Column className='flex-1' label={intl.formatMessage(messages.heading)}>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle title={intl.formatMessage(messages.subheading_add_new)} />
|
<CardTitle title={intl.formatMessage(messages.subheading_add_new)} />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<Search />
|
<Search />
|
||||||
{
|
{
|
||||||
loaded && searchAccountIds.size === 0 ? (
|
loaded && searchAccountIds.size === 0 ? (
|
||||||
<div className='aliases__accounts empty-column-indicator'>
|
<div
|
||||||
|
className='flex min-h-[160px] flex-1 items-center justify-center rounded-lg bg-primary-50 p-10 text-center text-gray-900 dark:bg-gray-700 dark:text-gray-300'
|
||||||
|
>
|
||||||
<FormattedMessage id='empty_column.aliases.suggestions' defaultMessage='There are no account suggestions available for the provided term.' />
|
<FormattedMessage id='empty_column.aliases.suggestions' defaultMessage='There are no account suggestions available for the provided term.' />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className='aliases__accounts mb-4'>
|
<div className='mb-4 overflow-y-auto'>
|
||||||
{searchAccountIds.map(accountId => <Account key={accountId} accountId={accountId} aliases={aliases} />)}
|
{searchAccountIds.map(accountId => <Account key={accountId} accountId={accountId} aliases={aliases} />)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -73,7 +75,7 @@ const Aliases = () => {
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle title={intl.formatMessage(messages.subheading_aliases)} />
|
<CardTitle title={intl.formatMessage(messages.subheading_aliases)} />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<div className='aliases-settings-panel'>
|
<div className='flex-1'>
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
scrollKey='aliases'
|
scrollKey='aliases'
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
|
|
|
@ -113,7 +113,9 @@ const NativeCaptchaField: React.FC<INativeCaptchaField> = ({ captcha, onChange,
|
||||||
return (
|
return (
|
||||||
<Stack space={2}>
|
<Stack space={2}>
|
||||||
<div className='flex w-full items-center justify-center rounded-md border border-solid border-gray-300 bg-white dark:border-gray-600'>
|
<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={intl.formatMessage(messages.captcha)} src={captcha.get('url')} onClick={onClick} />
|
<button className='!block space-x-2 !border-none !p-0 !py-2 !text-primary-600 hover:!underline focus:!ring-transparent focus:!ring-offset-0 dark:!text-accent-blue rtl:space-x-reverse' onClick={onClick}>
|
||||||
|
<img alt={intl.formatMessage(messages.captcha)} src={captcha.get('url')} />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
|
|
|
@ -49,7 +49,7 @@ const START_INDEX = 10000;
|
||||||
|
|
||||||
const List: Components['List'] = forwardRef((props, ref) => {
|
const List: Components['List'] = forwardRef((props, ref) => {
|
||||||
const { context, ...rest } = props;
|
const { context, ...rest } = props;
|
||||||
return <div ref={ref} {...rest} className='mb-2' />;
|
return <div ref={ref} {...rest} />;
|
||||||
});
|
});
|
||||||
|
|
||||||
const Scroller: Components['Scroller'] = forwardRef((props, ref) => {
|
const Scroller: Components['Scroller'] = forwardRef((props, ref) => {
|
||||||
|
|
|
@ -68,7 +68,7 @@ const ChatPage: React.FC<IChatPage> = ({ chatId }) => {
|
||||||
data-testid='chat-page'
|
data-testid='chat-page'
|
||||||
>
|
>
|
||||||
<Stack
|
<Stack
|
||||||
className={clsx('dark:inset col-span-9 overflow-hidden bg-gradient-to-r from-white to-gray-100 black:bg-black dark:bg-gray-900 dark:bg-none sm:col-span-3', {
|
className={clsx('col-span-9 overflow-hidden bg-gradient-to-r from-white to-gray-100 black:bg-black dark:inset-0 dark:bg-gray-900 dark:bg-none sm:col-span-3', {
|
||||||
'hidden sm:block': isSidebarHidden,
|
'hidden sm:block': isSidebarHidden,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
|
|
@ -127,7 +127,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
// List of elements that shouldn't collapse the composer when clicked
|
// List of elements that shouldn't collapse the composer when clicked
|
||||||
// FIXME: Make this less brittle
|
// FIXME: Make this less brittle
|
||||||
getClickableArea(),
|
getClickableArea(),
|
||||||
document.querySelector('.privacy-dropdown__dropdown'),
|
document.getElementById('privacy-dropdown'),
|
||||||
document.querySelector('em-emoji-picker'),
|
document.querySelector('em-emoji-picker'),
|
||||||
document.getElementById('modal-overlay'),
|
document.getElementById('modal-overlay'),
|
||||||
].some(element => element?.contains(e.target as any));
|
].some(element => element?.contains(e.target as any));
|
||||||
|
@ -217,7 +217,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
), [features, id]);
|
), [features, id]);
|
||||||
|
|
||||||
const composeModifiers = !condensed && (
|
const composeModifiers = !condensed && (
|
||||||
<Stack space={4} className='compose-form__modifiers'>
|
<Stack space={4} className='text-sm text-gray-900'>
|
||||||
<UploadForm composeId={id} onSubmit={handleSubmit} />
|
<UploadForm composeId={id} onSubmit={handleSubmit} />
|
||||||
<PollForm composeId={id} />
|
<PollForm composeId={id} />
|
||||||
|
|
||||||
|
|
|
@ -42,9 +42,10 @@ interface IPrivacyDropdownMenu {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onChange: (value: string | null) => void;
|
onChange: (value: string | null) => void;
|
||||||
unavailable?: boolean;
|
unavailable?: boolean;
|
||||||
|
active: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PrivacyDropdownMenu: React.FC<IPrivacyDropdownMenu> = ({ style, items, placement, value, onClose, onChange }) => {
|
const PrivacyDropdownMenu: React.FC<IPrivacyDropdownMenu> = ({ style, items, placement, value, onClose, onChange, active }) => {
|
||||||
const node = useRef<HTMLDivElement>(null);
|
const node = useRef<HTMLDivElement>(null);
|
||||||
const focusedItem = useRef<HTMLDivElement>(null);
|
const focusedItem = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
@ -125,15 +126,15 @@ const PrivacyDropdownMenu: React.FC<IPrivacyDropdownMenu> = ({ style, items, pla
|
||||||
// It should not be transformed when mounting because the resulting
|
// It should not be transformed when mounting because the resulting
|
||||||
// size will be used to determine the coordinate of the menu by
|
// size will be used to determine the coordinate of the menu by
|
||||||
// react-overlays
|
// react-overlays
|
||||||
<div className={clsx('privacy-dropdown__dropdown', placement)} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : undefined }} role='listbox' ref={node}>
|
<div id={'privacy-dropdown'} className={clsx('absolute z-[1000] ml-10 overflow-hidden rounded-md bg-white text-sm shadow-lg black:border black:border-gray-800 black:bg-black dark:bg-gray-900', { 'block shadow-md': active })} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : undefined, transformOrigin: placement === 'top' ? '50% 100%' : '50% 0' }} role='listbox' ref={node}>
|
||||||
{items.map(item => (
|
{items.map(item => (
|
||||||
<div role='option' tabIndex={0} key={item.value} data-index={item.value} onKeyDown={handleKeyDown} onClick={handleClick} className={clsx('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? focusedItem : null}>
|
<div role='option' tabIndex={0} key={item.value} data-index={item.value} onKeyDown={handleKeyDown} onClick={handleClick} className={clsx('group flex cursor-pointer p-2.5 text-sm text-gray-700 hover:bg-gray-100 black:hover:bg-gray-900 dark:text-gray-400 dark:hover:bg-gray-800', { 'bg-gray-100 dark:bg-gray-800 black:bg-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700': item.value === value })} aria-selected={item.value === value} ref={item.value === value ? focusedItem : null}>
|
||||||
<div className='privacy-dropdown__option__icon'>
|
<div className='mr-2.5 flex items-center justify-center rtl:ml-2.5 rtl:mr-0'>
|
||||||
<Icon src={item.icon} />
|
<Icon src={item.icon} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='privacy-dropdown__option__content'>
|
<div className={clsx('flex-auto text-primary-600 group-hover:text-black dark:text-primary-400 group-hover:dark:text-white', { 'group-active:text-black group-active:dark:text-white': item.value === value })}>
|
||||||
<strong>{item.text}</strong>
|
<strong className='block font-medium text-black dark:text-white'>{item.text}</strong>
|
||||||
{item.meta}
|
{item.meta}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -244,8 +245,8 @@ const PrivacyDropdown: React.FC<IPrivacyDropdown> = ({
|
||||||
const valueOption = options.find(item => item.value === value);
|
const valueOption = options.find(item => item.value === value);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('privacy-dropdown', placement, { active: open })} onKeyDown={handleKeyDown} ref={node}>
|
<div onKeyDown={handleKeyDown} ref={node}>
|
||||||
<div className={clsx('privacy-dropdown__value', { active: valueOption && options.indexOf(valueOption) === 0 })}>
|
<div className={clsx({ 'rouded-t-md': placement === 'top' && open })}>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={clsx({
|
className={clsx({
|
||||||
'text-gray-600 hover:text-gray-700 dark:hover:text-gray-500': !open,
|
'text-gray-600 hover:text-gray-700 dark:hover:text-gray-500': !open,
|
||||||
|
@ -266,6 +267,7 @@ const PrivacyDropdown: React.FC<IPrivacyDropdown> = ({
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
placement={placement}
|
placement={placement}
|
||||||
|
active={open}
|
||||||
/>
|
/>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -137,7 +137,7 @@ const SearchResults = () => {
|
||||||
searchResults = suggestions.map(suggestion => <AccountContainer key={suggestion.account} id={suggestion.account} />);
|
searchResults = suggestions.map(suggestion => <AccountContainer key={suggestion.account} id={suggestion.account} />);
|
||||||
} else if (loaded) {
|
} else if (loaded) {
|
||||||
noResultsMessage = (
|
noResultsMessage = (
|
||||||
<div className='empty-column-indicator'>
|
<div className='flex min-h-[160px] flex-1 items-center justify-center rounded-lg bg-primary-50 p-10 text-center text-gray-900 dark:bg-gray-700 dark:text-gray-300'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.search.accounts'
|
id='empty_column.search.accounts'
|
||||||
defaultMessage='There are no people results for "{term}"'
|
defaultMessage='There are no people results for "{term}"'
|
||||||
|
@ -179,7 +179,7 @@ const SearchResults = () => {
|
||||||
resultsIds = trendingStatuses;
|
resultsIds = trendingStatuses;
|
||||||
} else if (loaded) {
|
} else if (loaded) {
|
||||||
noResultsMessage = (
|
noResultsMessage = (
|
||||||
<div className='empty-column-indicator'>
|
<div className='flex min-h-[160px] flex-1 items-center justify-center rounded-lg bg-primary-50 p-10 text-center text-gray-900 dark:bg-gray-700 dark:text-gray-300'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.search.statuses'
|
id='empty_column.search.statuses'
|
||||||
defaultMessage='There are no posts results for "{term}"'
|
defaultMessage='There are no posts results for "{term}"'
|
||||||
|
@ -203,7 +203,7 @@ const SearchResults = () => {
|
||||||
searchResults = trends.map(hashtag => <Hashtag key={hashtag.name} hashtag={hashtag} />);
|
searchResults = trends.map(hashtag => <Hashtag key={hashtag.name} hashtag={hashtag} />);
|
||||||
} else if (loaded) {
|
} else if (loaded) {
|
||||||
noResultsMessage = (
|
noResultsMessage = (
|
||||||
<div className='empty-column-indicator'>
|
<div className='flex min-h-[160px] flex-1 items-center justify-center rounded-lg bg-primary-50 p-10 text-center text-gray-900 dark:bg-gray-700 dark:text-gray-300'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.search.hashtags'
|
id='empty_column.search.hashtags'
|
||||||
defaultMessage='There are no hashtags results for "{term}"'
|
defaultMessage='There are no hashtags results for "{term}"'
|
||||||
|
|
|
@ -10,7 +10,7 @@ interface IWarning {
|
||||||
const Warning: React.FC<IWarning> = ({ message }) => (
|
const Warning: React.FC<IWarning> = ({ message }) => (
|
||||||
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
|
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
|
||||||
{({ opacity, scaleX, scaleY }) => (
|
{({ opacity, scaleX, scaleY }) => (
|
||||||
<div className='compose-form__warning' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
|
<div className='compose-form-warning mb-2.5 rounded bg-accent-300 px-2.5 py-2 text-xs text-white shadow-md' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
|
||||||
{message}
|
{message}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -532,7 +532,7 @@ const AutosuggestPlugin = ({
|
||||||
? ReactDOM.createPortal(
|
? ReactDOM.createPortal(
|
||||||
<div
|
<div
|
||||||
className={clsx({
|
className={clsx({
|
||||||
'scroll-smooth snap-y snap-always will-change-scroll mt-6 overflow-y-auto max-h-56 relative w-max z-1000 shadow bg-white dark:bg-gray-900 rounded-lg py-1 space-y-0 dark:ring-2 dark:ring-primary-700 focus:outline-none': true,
|
'scroll-smooth snap-y snap-always will-change-scroll mt-6 overflow-y-auto max-h-56 relative w-max z-[1000] shadow bg-white dark:bg-gray-900 rounded-lg py-1 space-y-0 dark:ring-2 dark:ring-primary-700 focus:outline-none': true,
|
||||||
hidden: suggestionsHidden || suggestions.isEmpty(),
|
hidden: suggestionsHidden || suggestions.isEmpty(),
|
||||||
block: !suggestionsHidden && !suggestions.isEmpty(),
|
block: !suggestionsHidden && !suggestions.isEmpty(),
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -18,6 +18,7 @@ const CryptoIcon: React.FC<ICryptoIcon> = ({ ticker, title, className }): JSX.El
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<img
|
<img
|
||||||
|
className='w-full'
|
||||||
src={getIcon(ticker)}
|
src={getIcon(ticker)}
|
||||||
alt={title || ticker}
|
alt={title || ticker}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import externalLinkIcon from '@tabler/icons/outline/external-link.svg';
|
||||||
import { QRCodeCanvas as QRCode } from 'qrcode.react';
|
import { QRCodeCanvas as QRCode } from 'qrcode.react';
|
||||||
|
|
||||||
import CopyableInput from 'soapbox/components/copyable-input.tsx';
|
import CopyableInput from 'soapbox/components/copyable-input.tsx';
|
||||||
import Icon from 'soapbox/components/icon.tsx';
|
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
|
||||||
|
|
||||||
import { getExplorerUrl } from '../utils/block-explorer.ts';
|
import { getExplorerUrl } from '../utils/block-explorer.ts';
|
||||||
import { getTitle } from '../utils/coin-db.ts';
|
import { getTitle } from '../utils/coin-db.ts';
|
||||||
|
@ -20,22 +20,22 @@ const DetailedCryptoAddress: React.FC<IDetailedCryptoAddress> = ({ address, tick
|
||||||
const explorerUrl = getExplorerUrl(ticker, address);
|
const explorerUrl = getExplorerUrl(ticker, address);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='crypto-address'>
|
<div className='flex flex-col p-0'>
|
||||||
<div className='crypto-address__head'>
|
<div className='mb-1.5 flex items-center'>
|
||||||
<CryptoIcon
|
<CryptoIcon
|
||||||
className='crypto-address__icon'
|
className='mr-2.5 flex w-6 items-start justify-center'
|
||||||
ticker={ticker}
|
ticker={ticker}
|
||||||
title={title}
|
title={title}
|
||||||
/>
|
/>
|
||||||
<div className='crypto-address__title'>{title || ticker.toUpperCase()}</div>
|
<div className='font-bold'>{title || ticker.toUpperCase()}</div>
|
||||||
<div className='crypto-address__actions'>
|
<div className='ml-auto flex'>
|
||||||
{explorerUrl && <a href={explorerUrl} target='_blank'>
|
{explorerUrl && <a className='ml-2 text-gray-400' href={explorerUrl} target='_blank'>
|
||||||
<Icon src={externalLinkIcon} />
|
<SvgIcon size={20} src={externalLinkIcon} />
|
||||||
</a>}
|
</a>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{note && <div className='crypto-address__note'>{note}</div>}
|
{note && <div className='mb-2.5'>{note}</div>}
|
||||||
<div className='crypto-address__qrcode'>
|
<div className='mb-3 flex items-center justify-center p-2.5'>
|
||||||
<QRCode className='rounded-lg' value={address} includeMargin />
|
<QRCode className='rounded-lg' value={address} includeMargin />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -179,7 +179,7 @@ const EventDiscussion: React.FC<IEventDiscussion> = (props) => {
|
||||||
{me && <div className='border-b border-solid border-gray-200 p-2 pt-0 dark:border-gray-800'>
|
{me && <div className='border-b border-solid border-gray-200 p-2 pt-0 dark:border-gray-800'>
|
||||||
<ComposeForm id={`reply:${status.id}`} autoFocus={false} event={status.id} />
|
<ComposeForm id={`reply:${status.id}`} autoFocus={false} event={status.id} />
|
||||||
</div>}
|
</div>}
|
||||||
<div ref={node} className='thread p-0 shadow-none sm:p-2'>
|
<div ref={node} className='thread p-0 shadow-none black:bg-black dark:bg-primary-900 sm:p-2'>
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
id='thread'
|
id='thread'
|
||||||
ref={scroller}
|
ref={scroller}
|
||||||
|
|
|
@ -69,7 +69,7 @@ const Favourites: React.FC<IFavourites> = ({ params }) => {
|
||||||
if (isUnavailable) {
|
if (isUnavailable) {
|
||||||
return (
|
return (
|
||||||
<Column>
|
<Column>
|
||||||
<div className='empty-column-indicator'>
|
<div className='flex min-h-[160px] flex-1 items-center justify-center rounded-lg bg-primary-50 p-10 text-center text-gray-900 dark:bg-gray-700 dark:text-gray-300'>
|
||||||
<FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />
|
<FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />
|
||||||
</div>
|
</div>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
|
@ -188,7 +188,7 @@ const EditFilter: React.FC<IEditFilter> = ({ params }) => {
|
||||||
if (notFound) return <MissingIndicator />;
|
if (notFound) return <MissingIndicator />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column className='filter-settings-panel' label={intl.formatMessage(messages.subheading_add_new)}>
|
<Column label={intl.formatMessage(messages.subheading_add_new)}>
|
||||||
<Form onSubmit={handleAddNew}>
|
<Form onSubmit={handleAddNew}>
|
||||||
<FormGroup labelText={intl.formatMessage(messages.title)}>
|
<FormGroup labelText={intl.formatMessage(messages.title)}>
|
||||||
<Input
|
<Input
|
||||||
|
|
|
@ -60,7 +60,7 @@ const Filters = () => {
|
||||||
const emptyMessage = <FormattedMessage id='empty_column.filters' defaultMessage="You haven't created any muted words yet." />;
|
const emptyMessage = <FormattedMessage id='empty_column.filters' defaultMessage="You haven't created any muted words yet." />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column className='filter-settings-panel' label={intl.formatMessage(messages.heading)}>
|
<Column label={intl.formatMessage(messages.heading)}>
|
||||||
<HStack className='mb-4' space={2} justifyContent='end'>
|
<HStack className='mb-4' space={2} justifyContent='end'>
|
||||||
<Button
|
<Button
|
||||||
to='/filters/new'
|
to='/filters/new'
|
||||||
|
|
|
@ -44,7 +44,7 @@ const Followers: React.FC<IFollowers> = ({ params }) => {
|
||||||
|
|
||||||
if (isUnavailable) {
|
if (isUnavailable) {
|
||||||
return (
|
return (
|
||||||
<div className='empty-column-indicator'>
|
<div className='flex min-h-[160px] flex-1 items-center justify-center rounded-lg bg-primary-50 p-10 text-center text-gray-900 dark:bg-gray-700 dark:text-gray-300'>
|
||||||
<FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />
|
<FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -44,7 +44,7 @@ const Following: React.FC<IFollowing> = ({ params }) => {
|
||||||
|
|
||||||
if (isUnavailable) {
|
if (isUnavailable) {
|
||||||
return (
|
return (
|
||||||
<div className='empty-column-indicator'>
|
<div className='flex min-h-[160px] flex-1 items-center justify-center rounded-lg bg-primary-50 p-10 text-center text-gray-900 dark:bg-gray-700 dark:text-gray-300'>
|
||||||
<FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />
|
<FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -24,7 +24,7 @@ export const InputContainer: React.FC<IInputContainer> = (props) => {
|
||||||
return (
|
return (
|
||||||
<div className={containerClass}>
|
<div className={containerClass}>
|
||||||
{props.children}
|
{props.children}
|
||||||
{props.hint && <span className='hint'>{props.hint}</span>}
|
{props.hint && <span>{props.hint}</span>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -45,10 +45,10 @@ export const LabelInputContainer: React.FC<ILabelInputContainer> = ({ label, hin
|
||||||
return (
|
return (
|
||||||
<div className='label_input'>
|
<div className='label_input'>
|
||||||
<label htmlFor={id}>{label}</label>
|
<label htmlFor={id}>{label}</label>
|
||||||
<div className='label_input__wrapper'>
|
<div>
|
||||||
{childrenWithProps}
|
{childrenWithProps}
|
||||||
</div>
|
</div>
|
||||||
{hint && <span className='hint'>{hint}</span>}
|
{hint && <span>{hint}</span>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,7 +77,7 @@ const GroupGallery: React.FC<IGroupGallery> = (props) => {
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{(!isLoading && attachments.length === 0) && (
|
{(!isLoading && attachments.length === 0) && (
|
||||||
<div className='empty-column-indicator col-span-2 sm:col-span-3'>
|
<div className='col-span-2 flex min-h-[160px] flex-1 items-center justify-center rounded-lg bg-primary-50 p-10 text-center text-gray-900 dark:bg-gray-700 dark:text-gray-300 sm:col-span-3'>
|
||||||
<FormattedMessage id='account_gallery.none' defaultMessage='No media to show.' />
|
<FormattedMessage id='account_gallery.none' defaultMessage='No media to show.' />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -3,11 +3,11 @@ import clsx from 'clsx';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from 'soapbox/actions/lists.ts';
|
import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from 'soapbox/actions/lists.ts';
|
||||||
import Icon from 'soapbox/components/icon.tsx';
|
|
||||||
import Button from 'soapbox/components/ui/button.tsx';
|
import Button from 'soapbox/components/ui/button.tsx';
|
||||||
import Form from 'soapbox/components/ui/form.tsx';
|
import Form from 'soapbox/components/ui/form.tsx';
|
||||||
import HStack from 'soapbox/components/ui/hstack.tsx';
|
import HStack from 'soapbox/components/ui/hstack.tsx';
|
||||||
import Input from 'soapbox/components/ui/input.tsx';
|
import Input from 'soapbox/components/ui/input.tsx';
|
||||||
|
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
|
||||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ const Search = () => {
|
||||||
placeholder={intl.formatMessage(messages.search)}
|
placeholder={intl.formatMessage(messages.search)}
|
||||||
/>
|
/>
|
||||||
<div role='button' tabIndex={0} className='search__icon' onClick={handleClear}>
|
<div role='button' tabIndex={0} className='search__icon' onClick={handleClear}>
|
||||||
<Icon src={backspaceIcon} aria-label={intl.formatMessage(messages.search)} className={clsx('svg-icon--backspace', { active: hasValue })} />
|
<SvgIcon src={backspaceIcon} aria-label={intl.formatMessage(messages.search)} className={clsx('pointer-events-none absolute right-4 top-1/2 z-20 inline-block size-4.5 -translate-y-1/2 cursor-pointer text-[16px] text-gray-400 opacity-0 rtl:left-4 rtl:right-auto', { 'pointer-events-auto opacity-100': hasValue })} />
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,11 @@ import { randomIntFromInterval, generateText } from '../utils.ts';
|
||||||
|
|
||||||
/** Fake link preview to display while data is loading. */
|
/** Fake link preview to display while data is loading. */
|
||||||
const PlaceholderCard: React.FC = () => (
|
const PlaceholderCard: React.FC = () => (
|
||||||
<div className={clsx('status-card', {
|
<div className={clsx('flex overflow-hidden rounded-lg border border-solid border-gray-200 text-sm text-gray-800 no-underline dark:border-gray-800 dark:text-gray-200', {
|
||||||
'animate-pulse': true,
|
'animate-pulse': true,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div className='primary-500 w-2/5 rounded-l'> </div>
|
<div className='w-2/5 rounded-l'> </div>
|
||||||
|
|
||||||
<div className='flex w-3/5 flex-col justify-between break-words p-4 text-primary-50'>
|
<div className='flex w-3/5 flex-col justify-between break-words p-4 text-primary-50'>
|
||||||
<p>{generateText(randomIntFromInterval(5, 25))}</p>
|
<p>{generateText(randomIntFromInterval(5, 25))}</p>
|
||||||
|
|
|
@ -3,8 +3,8 @@ import PlaceholderStatus from './placeholder-status.tsx';
|
||||||
/** Fake material status to display while data is loading. */
|
/** Fake material status to display while data is loading. */
|
||||||
const PlaceholderMaterialStatus: React.FC = () => {
|
const PlaceholderMaterialStatus: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<div className='material-status' tabIndex={-1} aria-hidden>
|
<div className='pb-2.5' tabIndex={-1} aria-hidden>
|
||||||
<div className='material-status__status' tabIndex={0}>
|
<div className='rounded-[10px] py-[15px] pb-[10px] shadow-[0_0_6px_0_rgba(0,0,0,0.1)]' tabIndex={0}>
|
||||||
<PlaceholderStatus />
|
<PlaceholderStatus />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -33,7 +33,7 @@ const PlaceholderStatus: React.FC<IPlaceholderStatus> = ({ variant }) => (
|
||||||
</HStack>
|
</HStack>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='status__content-wrapper mt-4'>
|
<div className='status--content-wrapper mt-4'>
|
||||||
<PlaceholderStatusContent minLength={5} maxLength={120} />
|
<PlaceholderStatusContent minLength={5} maxLength={120} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
|
import clsx from 'clsx';
|
||||||
import noop from 'lodash/noop';
|
import noop from 'lodash/noop';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
import { toggleStatusReport } from 'soapbox/actions/reports.ts';
|
import { toggleStatusReport } from 'soapbox/actions/reports.ts';
|
||||||
import StatusContent from 'soapbox/components/status-content.tsx';
|
import StatusContent from 'soapbox/components/status-content.tsx';
|
||||||
import Toggle from 'soapbox/components/ui/toggle.tsx';
|
import Toggle from 'soapbox/components/ui/toggle.tsx';
|
||||||
|
import { MediaGallery, Video, Audio } from 'soapbox/features/ui/util/async-components.ts';
|
||||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||||
|
|
||||||
import { MediaGallery, Video, Audio } from '../../ui/util/async-components.ts';
|
|
||||||
|
|
||||||
interface IStatusCheckBox {
|
interface IStatusCheckBox {
|
||||||
id: string;
|
id: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
@ -21,6 +21,8 @@ const StatusCheckBox: React.FC<IStatusCheckBox> = ({ id, disabled }) => {
|
||||||
|
|
||||||
const onToggle: React.ChangeEventHandler<HTMLInputElement> = (e) => dispatch(toggleStatusReport(id, e.target.checked));
|
const onToggle: React.ChangeEventHandler<HTMLInputElement> = (e) => dispatch(toggleStatusReport(id, e.target.checked));
|
||||||
|
|
||||||
|
const mediaType = status?.media_attachments.get(0)?.type;
|
||||||
|
|
||||||
if (!status || status.reblog) {
|
if (!status || status.reblog) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -71,13 +73,17 @@ const StatusCheckBox: React.FC<IStatusCheckBox> = ({ id, disabled }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='status-check-box'>
|
<div className='flex items-center justify-between'>
|
||||||
<div className='status-check-box__status'>
|
<div className='py-2'>
|
||||||
<StatusContent status={status} />
|
<StatusContent status={status} />
|
||||||
<Suspense>{media}</Suspense>
|
<Suspense>
|
||||||
|
<div className={clsx('max-w-[250px]', { 'mt-2': mediaType === 'audio' || mediaType === 'video' })}>
|
||||||
|
{media}
|
||||||
|
</div>
|
||||||
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='status-check-box-toggle'>
|
<div className='flex flex-[0_0_auto] items-center justify-center p-2.5'>
|
||||||
<Toggle checked={checked} onChange={onToggle} disabled={disabled} />
|
<Toggle checked={checked} onChange={onToggle} disabled={disabled} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -31,8 +31,8 @@ const ScheduledStatus: React.FC<IScheduledStatus> = ({ statusId, ...other }) =>
|
||||||
const account = status.account;
|
const account = status.account;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('status__wrapper', `status__wrapper-${status.visibility}`, { 'status__wrapper-reply': !!status.in_reply_to_id })} tabIndex={0}>
|
<div className={clsx('status--wrapper')} tabIndex={0}>
|
||||||
<div className={clsx('status', `status-${status.visibility}`, { 'status-reply': !!status.in_reply_to_id })} data-id={status.id}>
|
<div className={clsx('status', { 'status-reply': !!status.in_reply_to_id })} data-id={status.id}>
|
||||||
<div className='mb-4'>
|
<div className='mb-4'>
|
||||||
<HStack justifyContent='between' alignItems='start'>
|
<HStack justifyContent='between' alignItems='start'>
|
||||||
<Account
|
<Account
|
||||||
|
|
|
@ -24,6 +24,7 @@ const SitePreview: React.FC<ISitePreview> = ({ soapbox }) => {
|
||||||
|
|
||||||
const dark = ['dark', 'black'].includes(userTheme as string) || (userTheme === 'system' && systemTheme === 'dark');
|
const dark = ['dark', 'black'].includes(userTheme as string) || (userTheme === 'system' && systemTheme === 'dark');
|
||||||
|
|
||||||
|
// eslint-disable-next-line tailwindcss/no-custom-classname
|
||||||
const bodyClass = clsx(
|
const bodyClass = clsx(
|
||||||
'site-preview',
|
'site-preview',
|
||||||
'align-center relative flex justify-center text-base',
|
'align-center relative flex justify-center text-base',
|
||||||
|
|
|
@ -105,7 +105,7 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
|
||||||
if (actualStatus.quote) {
|
if (actualStatus.quote) {
|
||||||
if (actualStatus.pleroma.get('quote_visible', true) === false) {
|
if (actualStatus.pleroma.get('quote_visible', true) === false) {
|
||||||
quote = (
|
quote = (
|
||||||
<div className='quoted-actualStatus-tombstone'>
|
<div>
|
||||||
<p><FormattedMessage id='status.quote_tombstone' defaultMessage='Post is unavailable.' /></p>
|
<p><FormattedMessage id='status.quote_tombstone' defaultMessage='Post is unavailable.' /></p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -121,8 +121,8 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='border-box'>
|
<div className='box-border'>
|
||||||
<div ref={node} className='detailed-actualStatus' tabIndex={-1}>
|
<div ref={node} tabIndex={-1}>
|
||||||
{renderStatusInfo()}
|
{renderStatusInfo()}
|
||||||
|
|
||||||
<div className='mb-4'>
|
<div className='mb-4'>
|
||||||
|
|
|
@ -12,7 +12,7 @@ const ColumnForbidden = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column label={intl.formatMessage(messages.title)}>
|
<Column label={intl.formatMessage(messages.title)}>
|
||||||
<div className='error-column'>
|
<div className='error-column flex min-h-[160px] flex-1 flex-col items-center justify-center rounded-lg bg-primary-50 p-10 text-center text-gray-900 dark:bg-gray-700 dark:text-gray-300'>
|
||||||
{intl.formatMessage(messages.body)}
|
{intl.formatMessage(messages.body)}
|
||||||
</div>
|
</div>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
|
@ -135,16 +135,16 @@ class ImageLoader extends PureComponent<IImageLoader> {
|
||||||
const { alt, src, width, height, onClick } = this.props;
|
const { alt, src, width, height, onClick } = this.props;
|
||||||
const { loading } = this.state;
|
const { loading } = this.state;
|
||||||
|
|
||||||
const className = clsx('image-loader', {
|
const className = 'relative size-full flex items-center justify-center flex-col';
|
||||||
'image-loader--loading': loading,
|
|
||||||
'image-loader--amorphous': !this.hasSize(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<canvas
|
<canvas
|
||||||
className='image-loader__preview-canvas'
|
className={clsx('max-h-[80%] max-w-full object-contain', { 'hidden': !this.hasSize() })}
|
||||||
|
style={{
|
||||||
|
background: 'url(\'../assets/images/void.png\') repeat',
|
||||||
|
}}
|
||||||
ref={this.setCanvasRef}
|
ref={this.setCanvasRef}
|
||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
|
|
|
@ -118,9 +118,9 @@ export default class ModalRoot extends PureComponent<IModalRoot> {
|
||||||
|
|
||||||
componentDidUpdate(prevProps: IModalRoot, prevState: any, { visible }: any) {
|
componentDidUpdate(prevProps: IModalRoot, prevState: any, { visible }: any) {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
document.body.classList.add('with-modals');
|
document.body.classList.add('overflow-hidden');
|
||||||
} else {
|
} else {
|
||||||
document.body.classList.remove('with-modals');
|
document.body.classList.remove('overflow-hidden');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ import clsx from 'clsx';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { spring } from 'react-motion';
|
import { spring } from 'react-motion';
|
||||||
|
|
||||||
import Icon from 'soapbox/components/icon.tsx';
|
|
||||||
import HStack from 'soapbox/components/ui/hstack.tsx';
|
import HStack from 'soapbox/components/ui/hstack.tsx';
|
||||||
|
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
|
||||||
import ReplyIndicator from 'soapbox/features/compose/components/reply-indicator.tsx';
|
import ReplyIndicator from 'soapbox/features/compose/components/reply-indicator.tsx';
|
||||||
|
|
||||||
import Motion from '../../util/optional-motion.tsx';
|
import Motion from '../../util/optional-motion.tsx';
|
||||||
|
@ -21,7 +21,7 @@ interface IActionsModal {
|
||||||
const ActionsModal: React.FC<IActionsModal> = ({ status, actions, onClick, onClose }) => {
|
const ActionsModal: React.FC<IActionsModal> = ({ status, actions, onClick, onClose }) => {
|
||||||
const renderAction = (action: MenuItem | null, i: number) => {
|
const renderAction = (action: MenuItem | null, i: number) => {
|
||||||
if (action === null) {
|
if (action === null) {
|
||||||
return <li key={`sep-${i}`} className='dropdown-menu__separator' />;
|
return <li key={`sep-${i}`} className='m-2 block h-px bg-gray-200 black:bg-gray-800 dark:bg-gray-600' />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { icon = null, text, meta = null, active = false, href = '#', destructive } = action;
|
const { icon = null, text, meta = null, active = false, href = '#', destructive } = action;
|
||||||
|
@ -35,12 +35,12 @@ const ActionsModal: React.FC<IActionsModal> = ({ status, actions, onClick, onClo
|
||||||
{...compProps}
|
{...compProps}
|
||||||
space={2.5}
|
space={2.5}
|
||||||
data-index={i}
|
data-index={i}
|
||||||
className={clsx('w-full', { active, destructive })}
|
className={clsx('flex w-full items-center px-4 py-3 text-left text-gray-700 no-underline hover:bg-gray-100 focus:bg-gray-100 dark:text-gray-500 dark:hover:bg-gray-800 dark:focus:bg-primary-800', { active, 'text-danger-600 dark:text-danger-400': destructive })}
|
||||||
element={Comp}
|
element={Comp}
|
||||||
>
|
>
|
||||||
{icon && <Icon title={text} src={icon} role='presentation' tabIndex={-1} />}
|
{icon && <SvgIcon title={text} className='size-6 min-w-5 stroke-[1.5]' src={icon} role='presentation' tabIndex={-1} />}
|
||||||
<div>
|
<div>
|
||||||
<div className={clsx({ 'actions-modal__item-label': !!meta })}>{text}</div>
|
<div className={clsx({ 'font-medium': !!meta })}>{text}</div>
|
||||||
<div>{meta}</div>
|
<div>{meta}</div>
|
||||||
</div>
|
</div>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
@ -51,18 +51,22 @@ const ActionsModal: React.FC<IActionsModal> = ({ status, actions, onClick, onClo
|
||||||
return (
|
return (
|
||||||
<Motion defaultStyle={{ top: 100 }} style={{ top: spring(0) }}>
|
<Motion defaultStyle={{ top: 100 }} style={{ top: spring(0) }}>
|
||||||
{({ top }) => (
|
{({ top }) => (
|
||||||
<div className='modal-root__modal actions-modal' style={{ top: `${top}%` }}>
|
<div className='pointer-events-auto relative z-[9999] m-auto flex max-h-[calc(100vh-3rem)] w-full max-w-lg flex-col overflow-hidden rounded-2xl bg-white text-gray-400 shadow-xl black:bg-black dark:bg-gray-900' style={{ top: `${top}%` }}>
|
||||||
{status && (
|
{status && (
|
||||||
<ReplyIndicator className='actions-modal__status rounded-b-none' status={status} hideActions />
|
<ReplyIndicator className='max-h-[300px] overflow-y-auto rounded-b-none' status={status} hideActions />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<ul className={clsx({ 'with-status': !!status })}>
|
<ul className={clsx({ ' max-h-[calc(80vh-75px)]': !!status }, 'my-2 max-h-[calc(100vh-147px)] shrink-0 overflow-y-auto')}>
|
||||||
{actions && actions.map(renderAction)}
|
{actions && actions.map(renderAction)}
|
||||||
|
|
||||||
<li className='dropdown-menu__separator' />
|
<li className='m-2 block h-px bg-gray-200 black:bg-gray-800 dark:bg-gray-600' />
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<button type='button' onClick={onClose}>
|
<button
|
||||||
|
type='button'
|
||||||
|
className='flex w-full items-center justify-center px-4 py-3 text-left text-gray-700 no-underline hover:bg-gray-100 focus:bg-gray-100 dark:text-gray-500 dark:hover:bg-gray-800 dark:focus:bg-primary-800'
|
||||||
|
onClick={onClose}
|
||||||
|
>
|
||||||
<FormattedMessage id='lightbox.close' defaultMessage='Close' />
|
<FormattedMessage id='lightbox.close' defaultMessage='Close' />
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -54,7 +54,7 @@ export const PuzzleCaptcha: React.FC<IPuzzleCaptcha> = ({ bg, puzzle, position,
|
||||||
return (
|
return (
|
||||||
<div id='drop-area' ref={ref} className='relative'>
|
<div id='drop-area' ref={ref} className='relative'>
|
||||||
<img
|
<img
|
||||||
className='drop-shadow-black absolute z-[101] w-[61px] drop-shadow-2xl hover:cursor-grab'
|
className='absolute z-[101] w-[61px] drop-shadow-2xl hover:cursor-grab'
|
||||||
src={puzzle}
|
src={puzzle}
|
||||||
alt=''
|
alt=''
|
||||||
onPointerDown={(e) => e.currentTarget.setPointerCapture(e.pointerId)}
|
onPointerDown={(e) => e.currentTarget.setPointerCapture(e.pointerId)}
|
||||||
|
|
|
@ -57,10 +57,10 @@ const CompareHistoryModal: React.FC<ICompareHistoryModal> = ({ onClose, statusId
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className='status__content' dangerouslySetInnerHTML={content} />
|
<div className='whitespace-normal p-0 pt-2.5 text-sm text-gray-700 dark:text-gray-500' dangerouslySetInnerHTML={content} />
|
||||||
|
|
||||||
{poll && (
|
{poll && (
|
||||||
<div className='poll'>
|
<div>
|
||||||
<Stack>
|
<Stack>
|
||||||
{version.poll.options.map((option: any) => (
|
{version.poll.options.map((option: any) => (
|
||||||
<HStack alignItems='center' className='p-1 text-gray-900 dark:text-gray-300'>
|
<HStack alignItems='center' className='p-1 text-gray-900 dark:text-gray-300'>
|
||||||
|
|
|
@ -7,7 +7,7 @@ const CryptoDonateModal: React.FC<ICryptoAddress & { onClose: () => void }> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal onClose={onClose} width='xs'>
|
<Modal onClose={onClose} width='xs'>
|
||||||
<div className='crypto-donate-modal'>
|
<div>
|
||||||
<DetailedCryptoAddress {...props} />
|
<DetailedCryptoAddress {...props} />
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -243,7 +243,7 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='media-modal pointer-events-auto fixed inset-0 z-[9999] h-full bg-gray-900/90'>
|
<div className='pointer-events-auto fixed inset-0 z-[9999] h-full bg-gray-900/90'>
|
||||||
<div
|
<div
|
||||||
className='absolute inset-0'
|
className='absolute inset-0'
|
||||||
role='presentation'
|
role='presentation'
|
||||||
|
|
|
@ -38,7 +38,7 @@ const ReplyMentionsModal: React.FC<IReplyMentionsModal> = ({ composeId, onClose
|
||||||
closeIcon={arrowLeftIcon}
|
closeIcon={arrowLeftIcon}
|
||||||
closePosition='left'
|
closePosition='left'
|
||||||
>
|
>
|
||||||
<div className='reply-mentions-modal__accounts'>
|
<div className='block min-h-[300px] flex-1 flex-row overflow-y-auto'>
|
||||||
{mentions.map(accountId => <Account composeId={composeId} key={accountId} accountId={accountId} author={author === accountId} />)}
|
{mentions.map(accountId => <Account composeId={composeId} key={accountId} accountId={accountId} author={author === accountId} />)}
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -115,8 +115,8 @@ const UnauthorizedModal: React.FC<IUnauthorizedModal> = ({ action, onClose, acco
|
||||||
secondaryAction={isOpen ? onRegister : undefined}
|
secondaryAction={isOpen ? onRegister : undefined}
|
||||||
secondaryText={isOpen ? <FormattedMessage id='account.register' defaultMessage='Sign up' /> : undefined}
|
secondaryText={isOpen ? <FormattedMessage id='account.register' defaultMessage='Sign up' /> : undefined}
|
||||||
>
|
>
|
||||||
<div className='remote-interaction-modal__content'>
|
<div className='flex flex-col gap-y-[10px]'>
|
||||||
<Form className='remote-interaction-modal__fields' onSubmit={onSubmit}>
|
<Form className='flex w-full flex-col gap-2.5' onSubmit={onSubmit}>
|
||||||
<Input
|
<Input
|
||||||
placeholder={intl.formatMessage(messages.accountPlaceholder)}
|
placeholder={intl.formatMessage(messages.accountPlaceholder)}
|
||||||
name='remote_follow[acct]'
|
name='remote_follow[acct]'
|
||||||
|
@ -126,12 +126,14 @@ const UnauthorizedModal: React.FC<IUnauthorizedModal> = ({ action, onClose, acco
|
||||||
onChange={onAccountChange}
|
onChange={onAccountChange}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<Button type='submit' theme='primary'>{button}</Button>
|
<Button className='self-end' type='submit' theme='primary'>{button}</Button>
|
||||||
</Form>
|
</Form>
|
||||||
<div className='remote-interaction-modal__divider'>
|
<div className='m-0 -mx-2.5 flex items-center gap-2.5'>
|
||||||
|
<div className='flex-1 border-b border-gray-300 dark:border-gray-600' />
|
||||||
<Text align='center'>
|
<Text align='center'>
|
||||||
<FormattedMessage id='remote_interaction.divider' defaultMessage='or' />
|
<FormattedMessage id='remote_interaction.divider' defaultMessage='or' />
|
||||||
</Text>
|
</Text>
|
||||||
|
<div className='flex-1 border-b border-gray-300 dark:border-gray-600' />
|
||||||
</div>
|
</div>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<Text size='lg' weight='medium'>
|
<Text size='lg' weight='medium'>
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
import HStack from 'soapbox/components/ui/hstack.tsx';
|
|
||||||
import Text from 'soapbox/components/ui/text.tsx';
|
|
||||||
import VerificationBadge from 'soapbox/components/verification-badge.tsx';
|
|
||||||
import { useSoapboxConfig } from 'soapbox/hooks/useSoapboxConfig.ts';
|
|
||||||
import { getAcct } from 'soapbox/utils/accounts.ts';
|
|
||||||
|
|
||||||
import type { Account } from 'soapbox/schemas/index.ts';
|
|
||||||
|
|
||||||
interface IDisplayName {
|
|
||||||
account: Pick<Account, 'id' | 'acct' | 'fqn' | 'verified' | 'display_name_html'>;
|
|
||||||
withSuffix?: boolean;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This component is different from other display name components because it displays the name inline.
|
|
||||||
*
|
|
||||||
* @param {IDisplayName} props - The properties for this component.
|
|
||||||
* @param {Pick<Account, 'id' | 'acct' | 'fqn' | 'verified' | 'display_name_html'>} props.account - The account object contains all the metadata for an account, such as the display name, ID, and more.
|
|
||||||
* @param {boolean} [props.withSuffix=true] - Determines whether to show the account suffix (eg, @danidfra).
|
|
||||||
*
|
|
||||||
* @returns {JSX.Element} The DisplayNameRow component.
|
|
||||||
*/
|
|
||||||
const DisplayNameRow: React.FC<IDisplayName> = ({ account, withSuffix = true }) => {
|
|
||||||
const { displayFqn = false } = useSoapboxConfig();
|
|
||||||
const { verified } = account;
|
|
||||||
|
|
||||||
const displayName = (
|
|
||||||
<HStack space={1} alignItems='center' justifyContent='center' grow>
|
|
||||||
<Text
|
|
||||||
size='sm'
|
|
||||||
weight='normal'
|
|
||||||
truncate
|
|
||||||
dangerouslySetInnerHTML={{ __html: account.display_name_html }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{verified && <VerificationBadge />}
|
|
||||||
</HStack>
|
|
||||||
);
|
|
||||||
|
|
||||||
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
|
||||||
const suffix = (<span className='display-name'>@{getAcct(account, displayFqn)}</span>);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='flex max-w-80 flex-col items-center justify-center text-center sm:flex-row sm:gap-2'>
|
|
||||||
{displayName}
|
|
||||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
|
||||||
<span className='hidden text-2xl font-bold sm:block'>-</span>
|
|
||||||
{withSuffix && suffix}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DisplayNameRow;
|
|
|
@ -47,7 +47,7 @@ const ZapSplit = ({ zapData, zapAmount, invoice, onNext, isLastStep, onFinish }:
|
||||||
<Account account={account} showProfileHoverCard={false} />
|
<Account account={account} showProfileHoverCard={false} />
|
||||||
</div>
|
</div>
|
||||||
</Stack>
|
</Stack>
|
||||||
<div className='bg-grey-500 dark:border-grey-800 -mx-4 w-full border-b border-solid sm:-mx-10' />
|
<div className='-mx-4 w-full border-b border-solid bg-gray-500 dark:border-gray-800 sm:-mx-10' />
|
||||||
|
|
||||||
<Stack justifyContent='center' alignItems='center' className='min-w-72 text-center' space={4}>
|
<Stack justifyContent='center' alignItems='center' className='min-w-72 text-center' space={4}>
|
||||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||||
|
@ -67,7 +67,7 @@ const ZapSplit = ({ zapData, zapAmount, invoice, onNext, isLastStep, onFinish }:
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<div className='flex justify-center'>
|
<div className='flex justify-center'>
|
||||||
<div className='box-shadow:none rounded-none border-0 border-b-2 p-0.5 text-center !ring-0 dark:bg-transparent'>
|
<div className='rounded-none border-0 border-b-2 p-0.5 text-center shadow-none !ring-0 dark:bg-transparent'>
|
||||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||||
<span className='!text-5xl font-bold'>{zapAmount}</span> sats
|
<span className='!text-5xl font-bold'>{zapAmount}</span> sats
|
||||||
</div>
|
</div>
|
||||||
|
@ -81,7 +81,7 @@ const ZapSplit = ({ zapData, zapAmount, invoice, onNext, isLastStep, onFinish }:
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</Stack>
|
</Stack>
|
||||||
{invoice && <div className='border-grey-500 mt-4 flex w-full border-t pt-4 sm:ml-4 sm:w-4/5 sm:border-l sm:border-t-0 sm:pl-4'>
|
{invoice && <div className='mt-4 flex w-full border-t border-gray-500 pt-4 sm:ml-4 sm:w-4/5 sm:border-l sm:border-t-0 sm:pl-4'>
|
||||||
<Stack space={6} className='relative m-auto' alignItems='center'>
|
<Stack space={6} className='relative m-auto' alignItems='center'>
|
||||||
<h3 className='text-xl font-bold'>
|
<h3 className='text-xl font-bold'>
|
||||||
{renderTitleQr()}
|
{renderTitleQr()}
|
||||||
|
|
|
@ -113,7 +113,7 @@ const Navbar = () => {
|
||||||
<HStack
|
<HStack
|
||||||
space={4}
|
space={4}
|
||||||
alignItems='center'
|
alignItems='center'
|
||||||
className={clsx('enter flex-1 lg:items-stretch', {
|
className={clsx('flex-1 lg:items-stretch', {
|
||||||
'justify-center lg:justify-start': account,
|
'justify-center lg:justify-start': account,
|
||||||
'justify-start': !account,
|
'justify-start': !account,
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -61,7 +61,7 @@ const PendingStatus: React.FC<IPendingStatus> = ({ idempotencyKey, className, mu
|
||||||
<div className={clsx('opacity-50', className)}>
|
<div className={clsx('opacity-50', className)}>
|
||||||
<div className={clsx('status', { 'status-reply': !!status.in_reply_to_id, muted })} data-id={status.id}>
|
<div className={clsx('status', { 'status-reply': !!status.in_reply_to_id, muted })} data-id={status.id}>
|
||||||
<Card
|
<Card
|
||||||
className={clsx(`status-${status.visibility}`, {
|
className={clsx({
|
||||||
'py-6 sm:p-5': !thread,
|
'py-6 sm:p-5': !thread,
|
||||||
'status-reply': !!status.in_reply_to_id,
|
'status-reply': !!status.in_reply_to_id,
|
||||||
})}
|
})}
|
||||||
|
@ -79,7 +79,7 @@ const PendingStatus: React.FC<IPendingStatus> = ({ idempotencyKey, className, mu
|
||||||
</HStack>
|
</HStack>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='status__content-wrapper'>
|
<div className='status--content-wrapper'>
|
||||||
<StatusReplyMentions status={status} />
|
<StatusReplyMentions status={status} />
|
||||||
|
|
||||||
<Stack space={4}>
|
<Stack space={4}>
|
||||||
|
|
|
@ -48,7 +48,7 @@ const ProfileFamiliarFollowers: React.FC<IProfileFamiliarFollowers> = ({ account
|
||||||
|
|
||||||
const accounts: Array<React.ReactNode> = familiarFollowers.map(account => !!account && (
|
const accounts: Array<React.ReactNode> = familiarFollowers.map(account => !!account && (
|
||||||
<HoverRefWrapper accountId={account.id} key={account.id} inline>
|
<HoverRefWrapper accountId={account.id} key={account.id} inline>
|
||||||
<Link className='mention inline-block' to={`/@${account.acct}`}>
|
<Link className='inline-block text-primary-600 hover:underline dark:text-accent-blue' to={`/@${account.acct}`}>
|
||||||
<HStack space={1} alignItems='center' grow>
|
<HStack space={1} alignItems='center' grow>
|
||||||
<Text
|
<Text
|
||||||
size='sm'
|
size='sm'
|
||||||
|
|
|
@ -124,7 +124,7 @@ class ZoomableImage extends PureComponent<IZoomableImage> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='zoomable-image'
|
className='relative flex size-full items-center justify-center'
|
||||||
ref={this.setContainerRef}
|
ref={this.setContainerRef}
|
||||||
style={{ overflow }}
|
style={{ overflow }}
|
||||||
>
|
>
|
||||||
|
@ -132,6 +132,7 @@ class ZoomableImage extends PureComponent<IZoomableImage> {
|
||||||
role='presentation'
|
role='presentation'
|
||||||
ref={this.setImageRef}
|
ref={this.setImageRef}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
|
className='size-auto max-h-[80%] max-w-full object-contain shadow-2xl'
|
||||||
title={alt}
|
title={alt}
|
||||||
src={src}
|
src={src}
|
||||||
style={{
|
style={{
|
||||||
|
|
|
@ -135,7 +135,7 @@ const ZapPayRequestForm = ({ account, status, onClose }: IZapPayRequestForm) =>
|
||||||
<div className='relative flex items-end justify-center gap-4'>
|
<div className='relative flex items-end justify-center gap-4'>
|
||||||
<Input
|
<Input
|
||||||
type='text' onChange={handleCustomAmount} value={zapAmount}
|
type='text' onChange={handleCustomAmount} value={zapAmount}
|
||||||
className='box-shadow:none max-w-20 rounded-none border-0 border-b-4 p-0 text-center !text-2xl font-bold !ring-0 dark:bg-transparent sm:max-w-28 sm:p-0.5 sm:!text-4xl'
|
className='max-w-20 rounded-none border-0 border-b-4 p-0 text-center !text-2xl font-bold shadow-none !ring-0 dark:bg-transparent sm:max-w-28 sm:p-0.5 sm:!text-4xl'
|
||||||
/>
|
/>
|
||||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||||
{hasZapSplit && <p className='absolute right-0 font-bold sm:-right-6 sm:text-xl'>sats</p>}
|
{hasZapSplit && <p className='absolute right-0 font-bold sm:-right-6 sm:text-xl'>sats</p>}
|
||||||
|
|
|
@ -1,30 +1,9 @@
|
||||||
@use 'variables';
|
|
||||||
@use 'fonts';
|
|
||||||
@use 'basics';
|
|
||||||
@use 'loading';
|
@use 'loading';
|
||||||
@use 'ui';
|
@use 'ui';
|
||||||
@use 'emoji-picker';
|
@use 'emoji-picker';
|
||||||
@use 'rtl';
|
|
||||||
@use 'accessibility';
|
@use 'accessibility';
|
||||||
@use 'navigation';
|
|
||||||
@use 'autosuggest';
|
|
||||||
|
|
||||||
// COMPONENTS
|
// COMPONENTS
|
||||||
@use 'components/buttons';
|
|
||||||
@use 'components/modal';
|
|
||||||
@use 'components/compose-form';
|
@use 'components/compose-form';
|
||||||
@use 'components/status';
|
@use 'components/status';
|
||||||
@use 'components/reply-mentions';
|
|
||||||
@use 'components/detailed-status';
|
|
||||||
@use 'components/media-gallery';
|
|
||||||
@use 'components/notification';
|
|
||||||
@use 'components/display-name';
|
|
||||||
@use 'components/columns';
|
|
||||||
@use 'components/search';
|
|
||||||
@use 'components/video-player';
|
|
||||||
@use 'components/audio-player';
|
|
||||||
@use 'components/crypto-donate';
|
|
||||||
@use 'components/aliases';
|
|
||||||
@use 'components/icon';
|
@use 'components/icon';
|
||||||
@use 'forms';
|
|
||||||
@use 'utilities';
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
.react-datepicker__input-container input {
|
|
||||||
// display: block;
|
|
||||||
// box-sizing: border-box;
|
|
||||||
// width: 100%;
|
|
||||||
// margin: 0;
|
|
||||||
// background: transparent;
|
|
||||||
// color: var(--primary-text-color);
|
|
||||||
// padding: 10px;
|
|
||||||
// font-family: inherit;
|
|
||||||
// font-size: 16px;
|
|
||||||
// resize: vertical;
|
|
||||||
// border: 0;
|
|
||||||
// outline: 0;
|
|
||||||
|
|
||||||
// &:focus {
|
|
||||||
// outline: 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @media screen and (max-width: 600px) {
|
|
||||||
// font-size: 16px;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-emoji {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
line-height: 18px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-emoji img {
|
|
||||||
display: block;
|
|
||||||
margin-right: 8px;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
body {
|
|
||||||
@apply antialiased;
|
|
||||||
-webkit-overflow-scrolling: touch;
|
|
||||||
-ms-overflow-style: -ms-autohiding-scrollbar;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.with-modals {
|
|
||||||
@apply overflow-hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: this is needed for React HotKeys performance. Removing this
|
|
||||||
// will cause severe performance degradation on Safari.
|
|
||||||
div[tabindex='-1']:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
::selection {
|
|
||||||
@apply bg-primary-600 text-white;
|
|
||||||
}
|
|
||||||
|
|
||||||
noscript {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emojione {
|
|
||||||
@apply w-4 h-4 -mt-[0.2ex] mb-[0.2ex] inline-block align-middle object-contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Virtuoso empty placeholder fix.
|
|
||||||
// https://gitlab.com/petyosi/soapbox-fe/-/commit/1e22c39934b60e5e186de804060ecfdf1955b506
|
|
||||||
div[data-viewport-type='window'] {
|
|
||||||
position: static !important;
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
.aliases {
|
|
||||||
&__accounts {
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
&.empty-column-indicator {
|
|
||||||
min-height: unset;
|
|
||||||
overflow-y: unset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.aliases-settings-panel {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
.audio-player {
|
|
||||||
@apply relative box-border overflow-hidden rounded-[10px] bg-black pb-11;
|
|
||||||
direction: ltr;
|
|
||||||
|
|
||||||
&.editable {
|
|
||||||
@apply rounded-none h-full;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__volume::before,
|
|
||||||
.video-player__seek::before {
|
|
||||||
@apply bg-white/10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__seek__buffer {
|
|
||||||
@apply bg-white/20;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__buttons button {
|
|
||||||
@apply text-current opacity-[75];
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
@apply text-current opacity-100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__time-sep,
|
|
||||||
.video-player__time-total,
|
|
||||||
.video-player__time-current {
|
|
||||||
@apply text-current;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__seek::before,
|
|
||||||
.video-player__seek__buffer,
|
|
||||||
.video-player__seek__progress {
|
|
||||||
@apply top-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__seek__handle {
|
|
||||||
@apply -top-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__controls {
|
|
||||||
@apply pt-2.5 bg-transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-spoiler-audio {
|
|
||||||
@apply relative mt-2 block cursor-pointer border-0 bg-cover bg-center bg-no-repeat;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
button {
|
|
||||||
font-family: inherit;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
.empty-column-indicator,
|
|
||||||
.error-column {
|
|
||||||
@apply bg-primary-50 dark:bg-gray-700 text-gray-900 dark:text-gray-300 text-center p-10 flex flex-1 items-center justify-center min-h-[160px] rounded-lg;
|
|
||||||
|
|
||||||
@supports (display: grid) { // hack to fix Chrome <57
|
|
||||||
contain: strict;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
@apply max-w-[400px];
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
@apply text-primary-600 dark:text-primary-400 no-underline hover:underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-column {
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.svg-icon {
|
|
||||||
width: 70px;
|
|
||||||
height: 70px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +1,9 @@
|
||||||
@use "../variables";
|
|
||||||
|
|
||||||
.compose-form {
|
.compose-form {
|
||||||
&__warning {
|
&__warning {
|
||||||
@apply text-xs mb-2.5 px-2.5 py-2 shadow-md rounded bg-accent-300 text-white;
|
@apply text-xs mb-2.5 px-2.5 py-2 shadow-md rounded bg-accent-300 text-white;
|
||||||
|
|
||||||
strong {
|
strong {
|
||||||
@apply font-medium;
|
@apply font-medium;
|
||||||
|
|
||||||
@each $lang in variables.$cjk-langs {
|
|
||||||
&:lang(#{$lang}) {
|
|
||||||
@apply font-bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
@ -169,12 +161,6 @@
|
||||||
|
|
||||||
strong {
|
strong {
|
||||||
@apply block font-medium text-black dark:text-white;
|
@apply block font-medium text-black dark:text-white;
|
||||||
|
|
||||||
@each $lang in variables.$cjk-langs {
|
|
||||||
&:lang(#{$lang}) {
|
|
||||||
@apply font-bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
.crypto-address {
|
|
||||||
@apply flex flex-col p-5;
|
|
||||||
|
|
||||||
&__head {
|
|
||||||
@apply flex items-center mb-1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
@apply font-bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__icon {
|
|
||||||
@apply flex items-start justify-center w-6 mr-2.5;
|
|
||||||
|
|
||||||
img {
|
|
||||||
@apply w-full;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__actions {
|
|
||||||
@apply flex ml-auto;
|
|
||||||
|
|
||||||
a {
|
|
||||||
@apply text-gray-400 ml-2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.svg-icon {
|
|
||||||
@apply h-4.5 w-4.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__note {
|
|
||||||
@apply mb-2.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__qrcode {
|
|
||||||
@apply flex items-center justify-center mb-3 p-2.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__address {
|
|
||||||
@apply mt-auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.crypto-donate-modal .crypto-address {
|
|
||||||
@apply p-0;
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
.thread {
|
|
||||||
@apply bg-white black:bg-black dark:bg-primary-900;
|
|
||||||
|
|
||||||
&__status {
|
|
||||||
@apply relative pb-4;
|
|
||||||
|
|
||||||
.status__wrapper {
|
|
||||||
@apply shadow-none p-0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status__content-wrapper {
|
|
||||||
@apply pl-[calc(42px+12px)] rtl:pl-0 rtl:pr-[calc(42px+12px)];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
.display-name {
|
|
||||||
display: block;
|
|
||||||
max-width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
bdi {
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__account {
|
|
||||||
position: relative;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,152 +0,0 @@
|
||||||
$media-compact-size: 50px;
|
|
||||||
|
|
||||||
.media-gallery {
|
|
||||||
@apply rounded-lg;
|
|
||||||
box-sizing: border-box;
|
|
||||||
overflow: hidden;
|
|
||||||
isolation: isolate;
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
|
|
||||||
&__item {
|
|
||||||
@apply rounded-sm;
|
|
||||||
border: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: block;
|
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&__icons {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
|
|
||||||
.svg-icon {
|
|
||||||
@apply h-24 w-24;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-overflow {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background: rgba(255, 255, 255, 0.75);
|
|
||||||
z-index: 2;
|
|
||||||
color: #333;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 50px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-thumbnail {
|
|
||||||
@apply text-gray-400;
|
|
||||||
cursor: zoom-in;
|
|
||||||
display: block;
|
|
||||||
text-decoration: none;
|
|
||||||
line-height: 0;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
video {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__preview {
|
|
||||||
@apply bg-gray-200 dark:bg-gray-900 rounded-lg;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 0;
|
|
||||||
|
|
||||||
&--hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__gifv {
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item-gifv-thumbnail {
|
|
||||||
@apply rounded-md;
|
|
||||||
cursor: zoom-in;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 1;
|
|
||||||
transform: none;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__gifv__label,
|
|
||||||
&__filename__label,
|
|
||||||
&__file-extension__label {
|
|
||||||
@apply pointer-events-none absolute bottom-1.5 left-1.5 z-[1] block bg-black/50 py-0.5 px-1.5 font-semibold text-white opacity-90;
|
|
||||||
font-size: 11px;
|
|
||||||
transition: opacity 0.1s ease;
|
|
||||||
line-height: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__gifv {
|
|
||||||
&.autoplay {
|
|
||||||
.media-gallery__gifv__label {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.media-gallery__gifv__label {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--compact {
|
|
||||||
height: $media-compact-size !important;
|
|
||||||
background: transparent;
|
|
||||||
|
|
||||||
.media-gallery__item {
|
|
||||||
width: $media-compact-size !important;
|
|
||||||
height: $media-compact-size !important;
|
|
||||||
inset: auto !important;
|
|
||||||
float: left !important;
|
|
||||||
margin-right: 5px;
|
|
||||||
|
|
||||||
&-overflow {
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__icons .svg-icon {
|
|
||||||
@apply h-8 w-8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-gallery__file-extension__label {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,177 +0,0 @@
|
||||||
.modal-root__modal {
|
|
||||||
pointer-events: auto;
|
|
||||||
display: flex;
|
|
||||||
z-index: 9999;
|
|
||||||
max-height: 100%;
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-modal {
|
|
||||||
.audio-player.detailed,
|
|
||||||
.extended-video-player {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.audio-player {
|
|
||||||
max-width: 800px;
|
|
||||||
max-height: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.extended-video-player {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
video {
|
|
||||||
@apply max-w-full max-h-[80%];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-modal {
|
|
||||||
@apply text-gray-900;
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
&__body {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 80vh;
|
|
||||||
width: 80vw;
|
|
||||||
max-width: 520px;
|
|
||||||
max-height: 420px;
|
|
||||||
position: relative;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
& > div {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 25px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
opacity: 0;
|
|
||||||
user-select: text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__footer {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 25px;
|
|
||||||
|
|
||||||
& > div {
|
|
||||||
min-width: 33px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions-modal {
|
|
||||||
@apply flex-col relative text-gray-400 overflow-hidden w-full max-w-lg m-auto bg-white black:bg-black dark:bg-gray-900 shadow-xl rounded-2xl;
|
|
||||||
max-height: calc(100vh - 3rem);
|
|
||||||
|
|
||||||
&__item-label {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-menu__separator {
|
|
||||||
@apply block m-2 h-[1px] bg-gray-200 dark:bg-gray-600 black:bg-gray-800;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__status {
|
|
||||||
@apply overflow-y-auto max-h-[300px];
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
@apply my-2 flex-shrink-0 overflow-y-auto;
|
|
||||||
max-height: calc(100vh - 147px);
|
|
||||||
|
|
||||||
&.with-status { max-height: calc(80vh - 75px); }
|
|
||||||
|
|
||||||
li:not(:empty) {
|
|
||||||
a,
|
|
||||||
button {
|
|
||||||
@apply flex items-center px-4 py-3 text-gray-700 dark:text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 focus:bg-gray-100 dark:focus:bg-primary-800 no-underline text-left;
|
|
||||||
|
|
||||||
&.destructive {
|
|
||||||
@apply text-danger-600 dark:text-danger-400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.svg-icon:first-child {
|
|
||||||
@apply min-w-[1.25rem] w-5 h-5;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
stroke-width: 1.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button[type='button'] {
|
|
||||||
@apply w-full justify-center text-center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.reply-mentions-modal__accounts {
|
|
||||||
display: block;
|
|
||||||
flex-direction: row;
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
min-height: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.remote-interaction-modal {
|
|
||||||
&__content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
row-gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__fields {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
button {
|
|
||||||
align-self: flex-end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__divider {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
margin: 0 -10px;
|
|
||||||
|
|
||||||
&::before,
|
|
||||||
&::after {
|
|
||||||
@apply border-b border-gray-300 dark:border-gray-600;
|
|
||||||
content: '';
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (width <= 895px) {
|
|
||||||
margin: 0;
|
|
||||||
border-radius: 6px;
|
|
||||||
height: unset !important;
|
|
||||||
width: 440px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (width <= 480px) {
|
|
||||||
width: 330px !important;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
.notification .status__wrapper {
|
|
||||||
@apply p-0 shadow-none rounded-none;
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
.reply-mentions {
|
|
||||||
@apply text-gray-700 dark:text-gray-600 mb-1 text-sm;
|
|
||||||
|
|
||||||
&__account {
|
|
||||||
@apply text-primary-600 dark:text-accent-blue hover:text-primary-700 dark:hover:text-accent-blue no-underline hover:underline inline-block;
|
|
||||||
direction: ltr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status__wrapper {
|
|
||||||
.reply-mentions {
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
span {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
@use "../fonts";
|
|
||||||
|
|
||||||
.search {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search__icon {
|
|
||||||
&::-moz-focus-inner {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-moz-focus-inner,
|
|
||||||
&:focus {
|
|
||||||
outline: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.svg-icon {
|
|
||||||
@apply right-4 rtl:left-4 rtl:right-auto text-gray-400;
|
|
||||||
@include fonts.font-size(16);
|
|
||||||
cursor: default;
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
z-index: 2;
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
pointer-events: auto;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.svg-icon--search.active {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.svg-icon--backspace {
|
|
||||||
cursor: pointer;
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,7 +15,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[column-type='filled'] .status__wrapper,
|
[column-type='filled'] .status--wrapper,
|
||||||
[column-type='filled'] .status-placeholder {
|
[column-type='filled'] .status-placeholder {
|
||||||
@apply bg-transparent dark:bg-transparent rounded-none shadow-none;
|
@apply bg-transparent dark:bg-transparent rounded-none shadow-none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,307 +0,0 @@
|
||||||
.detailed,
|
|
||||||
.fullscreen {
|
|
||||||
.video-player__volume__current,
|
|
||||||
.video-player__volume::before {
|
|
||||||
bottom: 27px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player__volume__handle {
|
|
||||||
bottom: 23px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-player {
|
|
||||||
@apply relative box-border max-w-full overflow-hidden rounded-[10px] bg-black text-white;
|
|
||||||
direction: ltr;
|
|
||||||
|
|
||||||
&.editable {
|
|
||||||
@apply rounded-none;
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
video {
|
|
||||||
display: block;
|
|
||||||
z-index: 1;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fullscreen {
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100% !important;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
video {
|
|
||||||
max-width: 100% !important;
|
|
||||||
max-height: 100% !important;
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100% !important;
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--inline {
|
|
||||||
video {
|
|
||||||
object-fit: contain;
|
|
||||||
max-height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__controls {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 2;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background: linear-gradient(0deg, #000000d9 0, #00000073 60%, transparent);
|
|
||||||
padding: 0 15px;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.1s ease;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buttons-bar {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
|
|
||||||
.video-player__download__icon {
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buttons {
|
|
||||||
display: flex;
|
|
||||||
flex: 0 1 auto;
|
|
||||||
min-width: 30px;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 16px;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
|
|
||||||
.player-button {
|
|
||||||
display: inline-block;
|
|
||||||
outline: 0;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
background: transparent;
|
|
||||||
padding: 5px 6px;
|
|
||||||
font-size: 16px;
|
|
||||||
border: 0;
|
|
||||||
color: rgba(#fff, 0.75);
|
|
||||||
|
|
||||||
.svg-icon {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time {
|
|
||||||
display: inline;
|
|
||||||
flex: 0 1 auto;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
margin: 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-sep,
|
|
||||||
&__time-total,
|
|
||||||
&__time-current {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-current {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-sep {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-sep,
|
|
||||||
&__time-total {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__volume {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
display: inline-flex;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 24px;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.no-reduce-motion & {
|
|
||||||
transition: all 100ms linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
overflow: visible;
|
|
||||||
width: 50px;
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
width: 50px;
|
|
||||||
background: rgba(#fff, 0.35);
|
|
||||||
border-radius: 4px;
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
height: 4px;
|
|
||||||
left: 0;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(0, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__current {
|
|
||||||
@apply bg-accent-500;
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
height: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
left: 0;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(0, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__handle {
|
|
||||||
@apply bg-accent-500;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 3;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
top: 50%;
|
|
||||||
left: 0;
|
|
||||||
margin-left: -6px;
|
|
||||||
transform: translate(0, -50%);
|
|
||||||
box-shadow: 1px 2px 6px #0003;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
.no-reduce-motion & {
|
|
||||||
transition: opacity 100ms linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active &__handle {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
padding: 2px 10px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #fff;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__seek {
|
|
||||||
cursor: pointer;
|
|
||||||
height: 24px;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
width: 100%;
|
|
||||||
background: rgba(#fff, 0.35);
|
|
||||||
border-radius: 4px;
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
height: 4px;
|
|
||||||
top: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__progress,
|
|
||||||
&__buffer {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
height: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
top: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__progress {
|
|
||||||
@apply bg-accent-500;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buffer {
|
|
||||||
background: rgba(#fff, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__handle {
|
|
||||||
@apply bg-accent-500;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 3;
|
|
||||||
opacity: 0;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
top: 10px;
|
|
||||||
margin-left: -6px;
|
|
||||||
box-shadow: 1px 2px 6px #0003;
|
|
||||||
|
|
||||||
.no-reduce-motion & {
|
|
||||||
transition: opacity 0.1s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.video-player__seek__handle {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.detailed,
|
|
||||||
&.fullscreen {
|
|
||||||
.video-player__buttons {
|
|
||||||
.player-button {
|
|
||||||
padding-top: 10px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-spoiler-video {
|
|
||||||
background-size: cover;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-top: 8px;
|
|
||||||
position: relative;
|
|
||||||
border: 0;
|
|
||||||
display: block;
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
@use 'sass:math';
|
|
||||||
|
|
||||||
// TYPEOGRAPHY MIXINS
|
|
||||||
|
|
||||||
// Use these mixins to define font-size and line-height
|
|
||||||
// html and body declaration allows developer to pass px value as argument
|
|
||||||
// Rendered css will default to "rem" and fall back to "px" for unsupported browsers
|
|
||||||
@mixin font-size($size) {
|
|
||||||
$rem: math.div($size, 10);
|
|
||||||
$px: $size;
|
|
||||||
font-size: #{$px + 'px'};
|
|
||||||
font-size: #{$rem + 'rem'};
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
select {
|
|
||||||
@apply pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md;
|
|
||||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-error::before,
|
|
||||||
.form-error::after {
|
|
||||||
border: solid transparent;
|
|
||||||
bottom: 100%;
|
|
||||||
content: '';
|
|
||||||
height: 0;
|
|
||||||
left: 10px;
|
|
||||||
pointer-events: none;
|
|
||||||
width: 0;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-error::before {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
border-bottom-color: rgba(254, 202, 202, var(--tw-bg-opacity));
|
|
||||||
border-width: 6px;
|
|
||||||
margin-left: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input.with_label.toggle .label_input {
|
|
||||||
display: flex;
|
|
||||||
font-size: 14px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
.thumb-navigation {
|
|
||||||
@apply fixed lg:hidden bottom-0 bg-white/90 black:bg-black/90 dark:bg-primary-900/90 backdrop-blur-md border-t border-solid border-gray-200 dark:border-gray-800 left-0 right-0 shadow-2xl w-full flex z-50;
|
|
||||||
padding-bottom: env(safe-area-inset-bottom); /* iOS PWA */
|
|
||||||
overflow-x: auto;
|
|
||||||
scrollbar-width: thin;
|
|
||||||
scrollbar-color: #fff;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
@apply px-2 py-2.5 space-y-1 flex flex-col flex-1 items-center text-gray-600 text-lg;
|
|
||||||
|
|
||||||
// padding: 8px 10px;
|
|
||||||
// display: flex;
|
|
||||||
// flex-direction: column;
|
|
||||||
// align-items: center;
|
|
||||||
// justify-content: end;
|
|
||||||
// color: var(--primary-text-color);
|
|
||||||
// text-decoration: none;
|
|
||||||
// font-size: 20px;
|
|
||||||
// width: 55px;
|
|
||||||
|
|
||||||
// span {
|
|
||||||
// margin-top: 1px;
|
|
||||||
// text-align: center;
|
|
||||||
// font-size: 1.2rem;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .svg-icon {
|
|
||||||
// width: 24px;
|
|
||||||
// height: 24px;
|
|
||||||
|
|
||||||
// svg {
|
|
||||||
// stroke-width: 1px;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
body.rtl {
|
|
||||||
direction: rtl;
|
|
||||||
|
|
||||||
.status {
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-right: 68px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table th,
|
|
||||||
.table td {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,7 +2,168 @@
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
body {
|
||||||
|
@apply antialiased;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
-ms-overflow-style: -ms-autohiding-scrollbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.rtl {
|
||||||
|
direction: rtl;
|
||||||
|
|
||||||
|
.status {
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 68px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th,
|
||||||
|
.table td {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
@apply bg-primary-600 text-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
div[data-viewport-type='window'] {
|
||||||
|
position: static !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div[tabindex='-1']:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
|
.status {
|
||||||
|
@apply min-h-[54px] cursor-default animate-fade opacity-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread {
|
||||||
|
@apply bg-white black:bg-black dark:bg-primary-900;
|
||||||
|
|
||||||
|
.status--content-wrapper {
|
||||||
|
@apply pl-[54px] rtl:pl-0 rtl:pr-[54px];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread__status {
|
||||||
|
@apply relative pb-4;
|
||||||
|
|
||||||
|
.status--wrapper {
|
||||||
|
@apply shadow-none p-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .status--wrapper {
|
||||||
|
@apply p-0 shadow-none rounded-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status--wrapper {
|
||||||
|
.reply-mentions {
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
span {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[column-type='filled'] .status--wrapper,
|
||||||
|
[column-type='filled'] .status-placeholder {
|
||||||
|
@apply bg-transparent dark:bg-transparent rounded-none shadow-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search__icon {
|
||||||
|
&::-moz-focus-inner {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-moz-focus-inner,
|
||||||
|
&:focus {
|
||||||
|
outline: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.focusable:focus,
|
||||||
|
.focusable-within:focus-within {
|
||||||
|
outline: 0;
|
||||||
|
@apply ring-2 ring-primary-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-column > span {
|
||||||
|
@apply max-w-[400px];
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-column {
|
||||||
|
.svg-icon {
|
||||||
|
width: 70px;
|
||||||
|
height: 70px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports (display: grid) {
|
||||||
|
contain: strict;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
@apply text-primary-600 dark:text-primary-400 no-underline hover:underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.mention {
|
||||||
|
@apply text-primary-600 dark:text-accent-blue hover:underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input.with_label.toggle .label_input {
|
||||||
|
display: flex;
|
||||||
|
font-size: 14px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divide-x-dot > *:not(:last-child)::after {
|
||||||
|
content: '·';
|
||||||
|
padding-right: 4px;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-lg img.emojione {
|
||||||
|
width: 36px !important;
|
||||||
|
height: 36px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emojione {
|
||||||
|
@apply w-4 h-4 -mt-[0.2ex] mb-[0.2ex] inline-block align-middle object-contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compose-form-warning {
|
||||||
|
strong {
|
||||||
|
@apply font-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: 500;
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:active,
|
||||||
|
&:focus {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide-scrollbar {
|
||||||
|
scrollbar-width: none; /* Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none; /* iOS PWA, Chrome */
|
||||||
|
}
|
||||||
|
|
||||||
.break-word-nested > p {
|
.break-word-nested > p {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@
|
||||||
.ui {
|
.ui {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0 0 calc(var(--thumb-navigation-height) + 86px);
|
padding: 0 0 calc(60px + env(safe-area-inset-bottom) + 86px);
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
.w-10i {
|
|
||||||
width: 2.5rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.z-1000 {
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.divide-x-dot > *:not(:last-child)::after {
|
|
||||||
content: '·';
|
|
||||||
padding-right: 4px;
|
|
||||||
padding-left: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mention {
|
|
||||||
@apply text-primary-600 dark:text-accent-blue hover:underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-lg img.emojione {
|
|
||||||
width: 36px !important;
|
|
||||||
height: 36px !important;
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Language codes that uses CJK fonts
|
|
||||||
/* stylelint-disable-next-line value-keyword-case -- locale filenames */
|
|
||||||
$cjk-langs: ja, ko, zh-CN, zh-HK, zh-TW;
|
|
||||||
|
|
||||||
// CSS variables
|
|
||||||
// NOTE: Prefer CSS variables whenever possible.
|
|
||||||
// They're future-proof and more flexible.
|
|
||||||
:root {
|
|
||||||
--thumb-navigation-height: calc(60px + env(safe-area-inset-bottom));
|
|
||||||
}
|
|
|
@ -63,6 +63,11 @@ const addAutoPlay = (html: string): string => {
|
||||||
const document = domParser.parseFromString(html, 'text/html').documentElement;
|
const document = domParser.parseFromString(html, 'text/html').documentElement;
|
||||||
const iframe = document.querySelector('iframe');
|
const iframe = document.querySelector('iframe');
|
||||||
|
|
||||||
|
if (iframe) {
|
||||||
|
iframe.style.width = '100%';
|
||||||
|
iframe.style.height = '100%';
|
||||||
|
}
|
||||||
|
|
||||||
if (iframe) {
|
if (iframe) {
|
||||||
const url = new URL(iframe.src);
|
const url = new URL(iframe.src);
|
||||||
const provider = new URL(iframe.src).host;
|
const provider = new URL(iframe.src).host;
|
||||||
|
|
|
@ -69,6 +69,7 @@ const config: Config = {
|
||||||
'greentext': true,
|
'greentext': true,
|
||||||
}),
|
}),
|
||||||
animation: {
|
animation: {
|
||||||
|
fade: 'fade 150ms linear',
|
||||||
'sonar-scale-4': 'sonar-scale-4 3s linear infinite',
|
'sonar-scale-4': 'sonar-scale-4 3s linear infinite',
|
||||||
'sonar-scale-3': 'sonar-scale-3 3s 0.5s linear infinite',
|
'sonar-scale-3': 'sonar-scale-3 3s 0.5s linear infinite',
|
||||||
'sonar-scale-2': 'sonar-scale-2 3s 1s linear infinite',
|
'sonar-scale-2': 'sonar-scale-2 3s 1s linear infinite',
|
||||||
|
@ -77,6 +78,10 @@ const config: Config = {
|
||||||
'leave': 'leave 150ms ease-in forwards',
|
'leave': 'leave 150ms ease-in forwards',
|
||||||
},
|
},
|
||||||
keyframes: {
|
keyframes: {
|
||||||
|
fade: {
|
||||||
|
'0%': { opacity: '0' },
|
||||||
|
'100%': { opacity: '1' },
|
||||||
|
},
|
||||||
'sonar-scale-4': {
|
'sonar-scale-4': {
|
||||||
from: { opacity: '0.4', transform: 'scale(1)' },
|
from: { opacity: '0.4', transform: 'scale(1)' },
|
||||||
to: { opacity: '0', transform: 'scale(4)' },
|
to: { opacity: '0', transform: 'scale(4)' },
|
||||||
|
|
Loading…
Reference in New Issue