Merge remote-tracking branch 'origin/develop' into gdpr
This commit is contained in:
commit
af6cb3a4c2
|
@ -0,0 +1,58 @@
|
||||||
|
{
|
||||||
|
// Place your soapbox-fe workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
|
||||||
|
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
|
||||||
|
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
|
||||||
|
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
|
||||||
|
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
|
||||||
|
// Placeholders with the same ids are connected.
|
||||||
|
// Example:
|
||||||
|
// "Print to console": {
|
||||||
|
// "scope": "javascript,typescript",
|
||||||
|
// "prefix": "log",
|
||||||
|
// "body": [
|
||||||
|
// "console.log('$1');",
|
||||||
|
// "$2"
|
||||||
|
// ],
|
||||||
|
// "description": "Log output to console"
|
||||||
|
// }
|
||||||
|
"React component": {
|
||||||
|
"scope": "typescriptreact",
|
||||||
|
"prefix": ["component", "react component"],
|
||||||
|
"body": [
|
||||||
|
"import React from 'react';",
|
||||||
|
"",
|
||||||
|
"interface I${1:Component} {",
|
||||||
|
"}",
|
||||||
|
"",
|
||||||
|
"/** ${1:Component} component. */",
|
||||||
|
"const ${1:Component}: React.FC<I${1:Component}> = () => {",
|
||||||
|
" return (",
|
||||||
|
" <></>",
|
||||||
|
" );",
|
||||||
|
"};",
|
||||||
|
"",
|
||||||
|
"export default ${1:Component};"
|
||||||
|
],
|
||||||
|
"description": "React component"
|
||||||
|
},
|
||||||
|
"React component test": {
|
||||||
|
"scope": "typescriptreact",
|
||||||
|
"prefix": ["test", "component test", "react component test"],
|
||||||
|
"body": [
|
||||||
|
"import React from 'react';",
|
||||||
|
"",
|
||||||
|
"import { render, screen } from 'soapbox/jest/test-helpers';",
|
||||||
|
"",
|
||||||
|
"import ${1:Component} from '${2:..}';",
|
||||||
|
"",
|
||||||
|
"describe('<${1:Component} />', () => {",
|
||||||
|
" it('renders', () => {",
|
||||||
|
" render(<${1:Component} />);",
|
||||||
|
"",
|
||||||
|
" expect(screen.getByTestId('${3:test}')).toBeInTheDocument();",
|
||||||
|
" });",
|
||||||
|
"});"
|
||||||
|
],
|
||||||
|
"description": "React component test"
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,7 +20,7 @@ const LoadGap: React.FC<ILoadGap> = ({ disabled, maxId, onClick }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className='load-more load-gap' disabled={disabled} onClick={handleClick} aria-label={intl.formatMessage(messages.load_more)}>
|
<button className='load-more load-gap' disabled={disabled} onClick={handleClick} aria-label={intl.formatMessage(messages.load_more)}>
|
||||||
<Icon id='ellipsis-h' />
|
<Icon src={require('@tabler/icons/dots.svg')} />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -215,7 +215,7 @@ class Item extends React.PureComponent {
|
||||||
alt={attachment.get('description')}
|
alt={attachment.get('description')}
|
||||||
title={attachment.get('description')}
|
title={attachment.get('description')}
|
||||||
>
|
>
|
||||||
<span className='media-gallery__item__icons'><Icon id='volume-up' /></span>
|
<span className='media-gallery__item__icons'><Icon src={require('@tabler/icons/volume.svg')} /></span>
|
||||||
<span className='media-gallery__file-extension__label'>{ext}</span>
|
<span className='media-gallery__file-extension__label'>{ext}</span>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
|
|
@ -36,6 +36,15 @@ const PollFooter: React.FC<IPollFooter> = ({ poll, showResults, selected }): JSX
|
||||||
intl.formatMessage(messages.closed) :
|
intl.formatMessage(messages.closed) :
|
||||||
<RelativeTimestamp weight='medium' timestamp={poll.expires_at} futureDate />;
|
<RelativeTimestamp weight='medium' timestamp={poll.expires_at} futureDate />;
|
||||||
|
|
||||||
|
let votesCount = null;
|
||||||
|
|
||||||
|
if (poll.voters_count !== null && poll.voters_count !== undefined) {
|
||||||
|
votesCount = <FormattedMessage id='poll.total_people' defaultMessage='{count, plural, one {# person} other {# people}}' values={{ count: poll.get('voters_count') }} />;
|
||||||
|
} else {
|
||||||
|
votesCount = <FormattedMessage id='poll.total_votes' defaultMessage='{count, plural, one {# vote} other {# votes}}' values={{ count: poll.get('votes_count') }} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack space={4} data-testid='poll-footer'>
|
<Stack space={4} data-testid='poll-footer'>
|
||||||
{(!showResults && poll?.multiple) && (
|
{(!showResults && poll?.multiple) && (
|
||||||
|
@ -58,11 +67,7 @@ const PollFooter: React.FC<IPollFooter> = ({ poll, showResults, selected }): JSX
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Text theme='muted' weight='medium'>
|
<Text theme='muted' weight='medium'>
|
||||||
<FormattedMessage
|
{votesCount}
|
||||||
id='poll.total_votes'
|
|
||||||
defaultMessage='{count, plural, one {# vote} other {# votes}}'
|
|
||||||
values={{ count: poll.votes_count }}
|
|
||||||
/>
|
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{poll.expires_at && (
|
{poll.expires_at && (
|
||||||
|
|
|
@ -110,7 +110,8 @@ const PollOption: React.FC<IPollOption> = (props): JSX.Element | null => {
|
||||||
|
|
||||||
if (!poll) return null;
|
if (!poll) return null;
|
||||||
|
|
||||||
const percent = poll.votes_count === 0 ? 0 : (option.votes_count / poll.votes_count) * 100;
|
const pollVotesCount = poll.voters_count || poll.votes_count;
|
||||||
|
const percent = pollVotesCount === 0 ? 0 : (option.votes_count / pollVotesCount) * 100;
|
||||||
const leading = poll.options.filterNot(other => other.title === option.title).every(other => option.votes_count >= other.votes_count);
|
const leading = poll.options.filterNot(other => other.title === option.title).every(other => option.votes_count >= other.votes_count);
|
||||||
const voted = poll.own_votes?.includes(index);
|
const voted = poll.own_votes?.includes(index);
|
||||||
const message = intl.formatMessage(messages.votes, { votes: option.votes_count });
|
const message = intl.formatMessage(messages.votes, { votes: option.votes_count });
|
||||||
|
|
|
@ -30,7 +30,7 @@ interface IReadMoreButton {
|
||||||
const ReadMoreButton: React.FC<IReadMoreButton> = ({ onClick }) => (
|
const ReadMoreButton: React.FC<IReadMoreButton> = ({ onClick }) => (
|
||||||
<button className='status__content__read-more-button' onClick={onClick}>
|
<button className='status__content__read-more-button' onClick={onClick}>
|
||||||
<FormattedMessage id='status.read_more' defaultMessage='Read more' />
|
<FormattedMessage id='status.read_more' defaultMessage='Read more' />
|
||||||
<Icon id='angle-right' fixedWidth />
|
<Icon className='inline-block h-5 w-5' src={require('@tabler/icons/chevron-right.svg')} fixedWidth />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,7 @@ class MediaItem extends ImmutablePureComponent {
|
||||||
const fileExtension = remoteURL.substr(fileExtensionLastIndex + 1).toUpperCase();
|
const fileExtension = remoteURL.substr(fileExtensionLastIndex + 1).toUpperCase();
|
||||||
thumbnail = (
|
thumbnail = (
|
||||||
<div className='media-gallery__item-thumbnail'>
|
<div className='media-gallery__item-thumbnail'>
|
||||||
<span className='media-gallery__item__icons'><Icon id='volume-up' /></span>
|
<span className='media-gallery__item__icons'><Icon src={require('@tabler/icons/volume.svg')} /></span>
|
||||||
<span className='media-gallery__file-extension__label'>{fileExtension}</span>
|
<span className='media-gallery__file-extension__label'>{fileExtension}</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -134,7 +134,7 @@ class MediaItem extends ImmutablePureComponent {
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
icon = (
|
icon = (
|
||||||
<span className='account-gallery__item__icons'>
|
<span className='account-gallery__item__icons'>
|
||||||
<Icon id='eye-slash' />
|
<Icon src={require('@tabler/icons/eye-off.svg')} />
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ const Aliases = () => {
|
||||||
<Text tag='span'>{alias}</Text>
|
<Text tag='span'>{alias}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center' role='button' tabIndex={0} onClick={handleFilterDelete} data-value={alias} aria-label={intl.formatMessage(messages.delete)}>
|
<div className='flex items-center' role='button' tabIndex={0} onClick={handleFilterDelete} data-value={alias} aria-label={intl.formatMessage(messages.delete)}>
|
||||||
<Icon className='pr-1.5 text-lg' id='times' />
|
<Icon className='mr-1.5' src={require('@tabler/icons/x.svg')} />
|
||||||
<Text weight='bold' theme='muted'><FormattedMessage id='aliases.aliases_list_delete' defaultMessage='Unlink alias' /></Text>
|
<Text weight='bold' theme='muted'><FormattedMessage id='aliases.aliases_list_delete' defaultMessage='Unlink alias' /></Text>
|
||||||
</div>
|
</div>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|
|
@ -13,8 +13,8 @@ import Motion from '../../ui/util/optional_motion';
|
||||||
import type { Map as ImmutableMap } from 'immutable';
|
import type { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
const bookIcon = require('@tabler/icons/book.svg');
|
const bookIcon = require('@tabler/icons/book.svg');
|
||||||
const fileAnalyticsIcon = require('@tabler/icons/file-analytics.svg');
|
|
||||||
const fileCodeIcon = require('@tabler/icons/file-code.svg');
|
const fileCodeIcon = require('@tabler/icons/file-code.svg');
|
||||||
|
const fileSpreadsheetIcon = require('@tabler/icons/file-spreadsheet.svg');
|
||||||
const fileTextIcon = require('@tabler/icons/file-text.svg');
|
const fileTextIcon = require('@tabler/icons/file-text.svg');
|
||||||
const fileZipIcon = require('@tabler/icons/file-zip.svg');
|
const fileZipIcon = require('@tabler/icons/file-zip.svg');
|
||||||
const defaultIcon = require('@tabler/icons/paperclip.svg');
|
const defaultIcon = require('@tabler/icons/paperclip.svg');
|
||||||
|
@ -39,9 +39,9 @@ export const MIMETYPE_ICONS: Record<string, string> = {
|
||||||
'application/xhtml+xml': fileCodeIcon,
|
'application/xhtml+xml': fileCodeIcon,
|
||||||
'application/xml': fileCodeIcon,
|
'application/xml': fileCodeIcon,
|
||||||
'application/epub+zip': bookIcon,
|
'application/epub+zip': bookIcon,
|
||||||
'application/vnd.oasis.opendocument.spreadsheet': fileAnalyticsIcon,
|
'application/vnd.oasis.opendocument.spreadsheet': fileSpreadsheetIcon,
|
||||||
'application/vnd.ms-excel': fileAnalyticsIcon,
|
'application/vnd.ms-excel': fileSpreadsheetIcon,
|
||||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': fileAnalyticsIcon,
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': fileSpreadsheetIcon,
|
||||||
'application/pdf': fileTextIcon,
|
'application/pdf': fileTextIcon,
|
||||||
'application/vnd.oasis.opendocument.presentation': presentationIcon,
|
'application/vnd.oasis.opendocument.presentation': presentationIcon,
|
||||||
'application/vnd.ms-powerpoint': presentationIcon,
|
'application/vnd.ms-powerpoint': presentationIcon,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { changeSettingImmediate } from 'soapbox/actions/settings';
|
||||||
import snackbar from 'soapbox/actions/snackbar';
|
import snackbar from 'soapbox/actions/snackbar';
|
||||||
import { Text } from 'soapbox/components/ui';
|
import { Text } from 'soapbox/components/ui';
|
||||||
import SvgIcon from 'soapbox/components/ui/icon/svg-icon';
|
import SvgIcon from 'soapbox/components/ui/icon/svg-icon';
|
||||||
|
import sourceCode from 'soapbox/utils/code';
|
||||||
|
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
|
|
||||||
|
@ -15,7 +16,23 @@ const messages = defineMessages({
|
||||||
leave: { id: 'developers.leave', defaultMessage: 'You have left developers' },
|
leave: { id: 'developers.leave', defaultMessage: 'You have left developers' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const Developers = () => {
|
interface IDashWidget {
|
||||||
|
to?: string,
|
||||||
|
onClick?: React.MouseEventHandler<HTMLButtonElement>,
|
||||||
|
children: React.ReactNode,
|
||||||
|
}
|
||||||
|
|
||||||
|
const DashWidget: React.FC<IDashWidget> = ({ to, onClick, children }) => {
|
||||||
|
const className = 'bg-gray-200 dark:bg-gray-600 p-4 rounded flex flex-col items-center justify-center space-y-2 hover:-translate-y-1 transition-transform';
|
||||||
|
|
||||||
|
if (to) {
|
||||||
|
return <Link className={className} to={to}>{children}</Link>;
|
||||||
|
} else {
|
||||||
|
return <button className={className} onClick={onClick}>{children}</button>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Developers: React.FC = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -29,57 +46,65 @@ const Developers = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column label={intl.formatMessage(messages.heading)}>
|
<>
|
||||||
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2'>
|
<Column label={intl.formatMessage(messages.heading)}>
|
||||||
<Link to='/developers/apps/create' className='bg-gray-200 dark:bg-gray-600 p-4 rounded flex flex-col items-center justify-center space-y-2 hover:-translate-y-1 transition-transform'>
|
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2'>
|
||||||
<SvgIcon src={require('@tabler/icons/apps.svg')} className='dark:text-gray-100' />
|
<DashWidget to='/developers/apps/create'>
|
||||||
|
<SvgIcon src={require('@tabler/icons/apps.svg')} className='dark:text-gray-100' />
|
||||||
|
|
||||||
<Text>
|
<Text>
|
||||||
<FormattedMessage id='developers.navigation.app_create_label' defaultMessage='Create an app' />
|
<FormattedMessage id='developers.navigation.app_create_label' defaultMessage='Create an app' />
|
||||||
</Text>
|
</Text>
|
||||||
</Link>
|
</DashWidget>
|
||||||
|
|
||||||
<Link to='/developers/settings_store' className='bg-gray-200 dark:bg-gray-600 p-4 rounded flex flex-col items-center justify-center space-y-2 hover:-translate-y-1 transition-transform'>
|
<DashWidget to='/developers/settings_store'>
|
||||||
<SvgIcon src={require('@tabler/icons/code-plus.svg')} className='dark:text-gray-100' />
|
<SvgIcon src={require('@tabler/icons/code-plus.svg')} className='dark:text-gray-100' />
|
||||||
|
|
||||||
<Text>
|
<Text>
|
||||||
<FormattedMessage id='developers.navigation.settings_store_label' defaultMessage='Settings store' />
|
<FormattedMessage id='developers.navigation.settings_store_label' defaultMessage='Settings store' />
|
||||||
</Text>
|
</Text>
|
||||||
</Link>
|
</DashWidget>
|
||||||
|
|
||||||
<Link to='/developers/timeline' className='bg-gray-200 dark:bg-gray-600 p-4 rounded flex flex-col items-center justify-center space-y-2 hover:-translate-y-1 transition-transform'>
|
<DashWidget to='/developers/timeline'>
|
||||||
<SvgIcon src={require('@tabler/icons/home.svg')} className='dark:text-gray-100' />
|
<SvgIcon src={require('@tabler/icons/home.svg')} className='dark:text-gray-100' />
|
||||||
|
|
||||||
<Text>
|
<Text>
|
||||||
<FormattedMessage id='developers.navigation.test_timeline_label' defaultMessage='Test timeline' />
|
<FormattedMessage id='developers.navigation.test_timeline_label' defaultMessage='Test timeline' />
|
||||||
</Text>
|
</Text>
|
||||||
</Link>
|
</DashWidget>
|
||||||
|
|
||||||
<Link to='/error' className='bg-gray-200 dark:bg-gray-600 p-4 rounded flex flex-col items-center justify-center space-y-2 hover:-translate-y-1 transition-transform'>
|
<DashWidget to='/error'>
|
||||||
<SvgIcon src={require('@tabler/icons/mood-sad.svg')} className='dark:text-gray-100' />
|
<SvgIcon src={require('@tabler/icons/mood-sad.svg')} className='dark:text-gray-100' />
|
||||||
|
|
||||||
<Text>
|
<Text>
|
||||||
<FormattedMessage id='developers.navigation.intentional_error_label' defaultMessage='Trigger an error' />
|
<FormattedMessage id='developers.navigation.intentional_error_label' defaultMessage='Trigger an error' />
|
||||||
</Text>
|
</Text>
|
||||||
</Link>
|
</DashWidget>
|
||||||
|
|
||||||
<Link to='/error/network' className='bg-gray-200 dark:bg-gray-600 p-4 rounded flex flex-col items-center justify-center space-y-2 hover:-translate-y-1 transition-transform'>
|
<DashWidget to='/error/network'>
|
||||||
<SvgIcon src={require('@tabler/icons/refresh.svg')} className='dark:text-gray-100' />
|
<SvgIcon src={require('@tabler/icons/refresh.svg')} className='dark:text-gray-100' />
|
||||||
|
|
||||||
<Text>
|
<Text>
|
||||||
<FormattedMessage id='developers.navigation.network_error_label' defaultMessage='Network error' />
|
<FormattedMessage id='developers.navigation.network_error_label' defaultMessage='Network error' />
|
||||||
</Text>
|
</Text>
|
||||||
</Link>
|
</DashWidget>
|
||||||
|
|
||||||
<button onClick={leaveDevelopers} className='bg-gray-200 dark:bg-gray-600 p-4 rounded flex flex-col items-center justify-center space-y-2 hover:-translate-y-1 transition-transform'>
|
<DashWidget onClick={leaveDevelopers}>
|
||||||
<SvgIcon src={require('@tabler/icons/logout.svg')} className='dark:text-gray-100' />
|
<SvgIcon src={require('@tabler/icons/logout.svg')} className='dark:text-gray-100' />
|
||||||
|
|
||||||
<Text>
|
<Text>
|
||||||
<FormattedMessage id='developers.navigation.leave_developers_label' defaultMessage='Leave developers' />
|
<FormattedMessage id='developers.navigation.leave_developers_label' defaultMessage='Leave developers' />
|
||||||
</Text>
|
</Text>
|
||||||
</button>
|
</DashWidget>
|
||||||
|
</div>
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<div className='p-4'>
|
||||||
|
<Text align='center' theme='subtle' size='sm'>
|
||||||
|
{sourceCode.displayName} {sourceCode.version}
|
||||||
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
</Column>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ class InstanceRestrictions extends ImmutablePureComponent {
|
||||||
if (!fullMediaRemoval && media_nsfw) {
|
if (!fullMediaRemoval && media_nsfw) {
|
||||||
items.push((
|
items.push((
|
||||||
<Text key='media_nsfw' className='flex items-center gap-2' theme='muted'>
|
<Text key='media_nsfw' className='flex items-center gap-2' theme='muted'>
|
||||||
<Icon id='eye-slash' />
|
<Icon src={require('@tabler/icons/eye-off.svg')} />
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='federation_restriction.media_nsfw'
|
id='federation_restriction.media_nsfw'
|
||||||
defaultMessage='Attachments marked NSFW'
|
defaultMessage='Attachments marked NSFW'
|
||||||
|
@ -117,7 +117,7 @@ class InstanceRestrictions extends ImmutablePureComponent {
|
||||||
if (remoteInstance.getIn(['federation', 'reject']) === true) {
|
if (remoteInstance.getIn(['federation', 'reject']) === true) {
|
||||||
return (
|
return (
|
||||||
<Text className='flex items-center gap-2' theme='muted'>
|
<Text className='flex items-center gap-2' theme='muted'>
|
||||||
<Icon id='times' />
|
<Icon src={require('@tabler/icons/x.svg')} />
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='remote_instance.federation_panel.restricted_message'
|
id='remote_instance.federation_panel.restricted_message'
|
||||||
defaultMessage='{siteTitle} blocks all activities from {host}.'
|
defaultMessage='{siteTitle} blocks all activities from {host}.'
|
||||||
|
@ -141,7 +141,7 @@ class InstanceRestrictions extends ImmutablePureComponent {
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Text className='flex items-center gap-2' theme='muted'>
|
<Text className='flex items-center gap-2' theme='muted'>
|
||||||
<Icon id='check' />
|
<Icon src={require('@tabler/icons/check.svg')} />
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='remote_instance.federation_panel.no_restrictions_message'
|
id='remote_instance.federation_panel.no_restrictions_message'
|
||||||
defaultMessage='{siteTitle} has placed no restrictions on {host}.'
|
defaultMessage='{siteTitle} has placed no restrictions on {host}.'
|
||||||
|
|
|
@ -216,7 +216,7 @@ const Filters = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='filter__delete' role='button' tabIndex={0} onClick={handleFilterDelete} data-value={filter.id} aria-label={intl.formatMessage(messages.delete)}>
|
<div className='filter__delete' role='button' tabIndex={0} onClick={handleFilterDelete} data-value={filter.id} aria-label={intl.formatMessage(messages.delete)}>
|
||||||
<Icon className='filter__delete-icon' id='times' />
|
<Icon className='filter__delete-icon' src={require('@tabler/icons/x.svg')} />
|
||||||
<span className='filter__delete-label'><FormattedMessage id='filters.filters_list_delete' defaultMessage='Delete' /></span>
|
<span className='filter__delete-label'><FormattedMessage id='filters.filters_list_delete' defaultMessage='Delete' /></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -38,7 +38,7 @@ const BoostModal: React.FC<IBoostModal> = ({ status, onReblog, onClose }) => {
|
||||||
<ReplyIndicator status={status} hideActions />
|
<ReplyIndicator status={status} hideActions />
|
||||||
|
|
||||||
<Text>
|
<Text>
|
||||||
<FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' /></span> }} />
|
<FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon className='inline-block align-middle' src={require('@tabler/icons/repeat.svg')} /></span> }} />
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -65,7 +65,7 @@ const ProfileField: React.FC<IProfileField> = ({ field }) => {
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Text tag='span' dangerouslySetInnerHTML={{ __html: field.value_emojified }} />
|
<Text className='break-words overflow-hidden' tag='span' dangerouslySetInnerHTML={{ __html: field.value_emojified }} />
|
||||||
</HStack>
|
</HStack>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
|
@ -178,7 +178,10 @@ a .account__avatar {
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
font-size: 24px;
|
|
||||||
|
.svg-icon {
|
||||||
|
@apply h-6 w-6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,14 +87,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter__delete {
|
.filter__delete {
|
||||||
@apply flex items-baseline h-5 m-2.5 cursor-pointer;
|
@apply flex items-center h-5 m-2.5 cursor-pointer;
|
||||||
|
|
||||||
span.filter__delete-label {
|
span.filter__delete-label {
|
||||||
@apply text-gray-500 dark:text-gray-400 font-semibold;
|
@apply text-gray-500 dark:text-gray-400 font-semibold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter__delete-icon {
|
.filter__delete-icon {
|
||||||
@apply px-1 mx-auto text-base text-gray-500 dark:text-gray-400;
|
@apply mx-1 text-gray-500 dark:text-gray-400;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,10 @@
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
font-size: 100px;
|
|
||||||
|
.svg-icon {
|
||||||
|
@apply h-24 w-24;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-overflow {
|
&-overflow {
|
||||||
|
@ -207,8 +210,8 @@ $media-compact-size: 50px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__icons {
|
&__icons .svg-icon {
|
||||||
font-size: 30px;
|
@apply h-8 w-8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.status__content__read-more-button {
|
.status__content__read-more-button {
|
||||||
@apply block text-gray-900 dark:text-gray-300 border-0 bg-transparent p-0 pt-2 hover:underline active:underline;
|
@apply flex items-center text-gray-900 dark:text-gray-300 border-0 bg-transparent p-0 pt-2 hover:underline active:underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-link {
|
.status-link {
|
||||||
|
|
|
@ -132,20 +132,19 @@
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: 0;
|
border: 0;
|
||||||
font-size: inherit;
|
|
||||||
text-align: center;
|
|
||||||
line-height: inherit;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
clear: both;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus {
|
||||||
background: var(--brand-color--faint);
|
background: var(--brand-color--faint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.svg-icon {
|
||||||
|
@apply mx-auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.load-gap {
|
.load-gap {
|
||||||
|
|
|
@ -1,13 +1,32 @@
|
||||||
import { danger, warn, message } from 'danger';
|
import { danger, warn, message } from 'danger';
|
||||||
|
|
||||||
|
// Docs changes
|
||||||
const docs = danger.git.fileMatch('docs/**/*.md');
|
const docs = danger.git.fileMatch('docs/**/*.md');
|
||||||
const app = danger.git.fileMatch('app/**/*.(js|ts|tsx)');
|
|
||||||
const tests = danger.git.fileMatch('**/__tests__/**');
|
|
||||||
|
|
||||||
if (docs.edited) {
|
if (docs.edited) {
|
||||||
message('Thanks - We :heart: our [documentarians](http://www.writethedocs.org/)!');
|
message('Thanks - We :heart: our [documentarians](http://www.writethedocs.org/)!');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app.modified && !tests.modified) {
|
// UI components
|
||||||
warn('You have app changes without tests.');
|
const uiCode = danger.git.fileMatch('app/soapbox/components/ui/**');
|
||||||
|
const uiTests = danger.git.fileMatch('app/soapbox/components/ui/**/__tests__/**');
|
||||||
|
|
||||||
|
if (uiCode.modified && !uiTests.modified) {
|
||||||
|
warn('You have UI changes (`soapbox/components/ui`) without tests.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
const actionsCode = danger.git.fileMatch('app/soapbox/actions/**');
|
||||||
|
const actionsTests = danger.git.fileMatch('app/soapbox/actions/**__tests__/**');
|
||||||
|
|
||||||
|
if (actionsCode.modified && !actionsTests.modified) {
|
||||||
|
warn('You have actions changes (`soapbox/actions`) without tests.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reducers
|
||||||
|
const reducersCode = danger.git.fileMatch('app/soapbox/reducers/**');
|
||||||
|
const reducersTests = danger.git.fileMatch('app/soapbox/reducers/**__tests__/**');
|
||||||
|
|
||||||
|
if (reducersCode.modified && !reducersTests.modified) {
|
||||||
|
warn('You have reducer changes (`soapbox/reducers`) without tests.');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue