Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
merge-requests/1196/head
marcin mikołajczak 2022-04-10 12:46:25 +02:00
rodzic 4f358b9632
commit 98ff406ddf
17 zmienionych plików z 177 dodań i 224 usunięć

Wyświetl plik

@ -6,7 +6,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Textarea from 'react-textarea-autosize';
import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
import AutosuggestAccount from '../features/compose/components/autosuggest_account';
import { isRtl } from '../rtl';
import AutosuggestEmoji from './autosuggest_emoji';
@ -205,7 +205,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
inner = suggestion;
key = suggestion;
} else {
inner = <AutosuggestAccountContainer id={suggestion} />;
inner = <AutosuggestAccount id={suggestion} />;
key = suggestion;
}

Wyświetl plik

@ -1,20 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import { useSelector } from 'react-redux';
import Account from '../../../components/account';
import { makeGetAccount } from '../../../selectors';
const AutosuggestAccount = ({ id }) => {
const getAccount = makeGetAccount();
const account = useSelector((state) => getAccount(state, id));
return <Account account={account} hideActions showProfileHoverCard={false} />;
};
AutosuggestAccount.propTypes = {
id: PropTypes.number.isRequired,
};
export default AutosuggestAccount;

Wyświetl plik

@ -0,0 +1,21 @@
import React from 'react';
import Account from 'soapbox/components/account';
import { useAppSelector } from 'soapbox/hooks';
import { makeGetAccount } from 'soapbox/selectors';
interface IAutosuggestAccount {
id: string,
}
const AutosuggestAccount: React.FC<IAutosuggestAccount> = ({ id }) => {
const getAccount = makeGetAccount();
const account = useAppSelector((state) => getAccount(state, id));
if (!account) return null;
return <Account account={account} hideActions showProfileHoverCard={false} />;
};
export default AutosuggestAccount;

Wyświetl plik

@ -15,6 +15,7 @@ import AutosuggestTextarea from '../../../components/autosuggest_textarea';
import { Button } from '../../../components/ui';
import { isMobile } from '../../../is_mobile';
import ReplyMentions from '../components/reply_mentions';
import UploadForm from '../components/upload_form';
import Warning from '../components/warning';
import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container';
import MarkdownButtonContainer from '../containers/markdown_button_container';
@ -27,7 +28,6 @@ import ScheduleButtonContainer from '../containers/schedule_button_container';
import ScheduleFormContainer from '../containers/schedule_form_container';
import SpoilerButtonContainer from '../containers/spoiler_button_container';
import UploadButtonContainer from '../containers/upload_button_container';
import UploadFormContainer from '../containers/upload_form_container';
import WarningContainer from '../containers/warning_container';
import { countableText } from '../util/counter';
@ -354,7 +354,7 @@ class ComposeForm extends ImmutablePureComponent {
{
!condensed &&
<div className='compose-form__modifiers'>
<UploadFormContainer />
<UploadForm />
<PollFormContainer />
<ScheduleFormContainer />
</div>

Wyświetl plik

@ -1,31 +0,0 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import { length } from 'stringz';
export default class TextCharacterCounter extends React.PureComponent {
static propTypes = {
text: PropTypes.string.isRequired,
max: PropTypes.number.isRequired,
};
checkRemainingText(diff) {
return (
<span
className={classNames('text-sm font-semibold', {
'text-gray-400': diff >= 0,
'text-danger-600': diff < 0,
})}
>
{diff}
</span>
);
}
render() {
const diff = this.props.max - length(this.props.text);
return this.checkRemainingText(diff);
}
}

Wyświetl plik

@ -0,0 +1,28 @@
import classNames from 'classnames';
import React from 'react';
import { length } from 'stringz';
interface ITextCharacterCounter {
max: number,
text: string,
}
const TextCharacterCounter: React.FC<ITextCharacterCounter> = ({ text, max }) => {
const checkRemainingText = (diff: number) => {
return (
<span
className={classNames('text-sm font-semibold', {
'text-gray-400': diff >= 0,
'text-danger-600': diff < 0,
})}
>
{diff}
</span>
);
};
const diff = max - length(text);
return checkRemainingText(diff);
};
export default TextCharacterCounter;

Wyświetl plik

@ -1,37 +0,0 @@
import classNames from 'classnames';
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
// import SensitiveButtonContainer from '../containers/sensitive_button_container';
import UploadProgress from '../components/upload-progress';
import UploadContainer from '../containers/upload_container';
export default class UploadForm extends ImmutablePureComponent {
static propTypes = {
mediaIds: ImmutablePropTypes.list.isRequired,
};
render() {
const { mediaIds } = this.props;
const classes = classNames('compose-form__uploads-wrapper', {
'contains-media': mediaIds.size !== 0,
});
return (
<div className='compose-form__upload-wrapper'>
<UploadProgress />
<div className={classes}>
{mediaIds.map(id => (
<UploadContainer id={id} key={id} />
))}
</div>
{/* {!mediaIds.isEmpty() && <SensitiveButtonContainer />} */}
</div>
);
}
}

Wyświetl plik

@ -0,0 +1,33 @@
import classNames from 'classnames';
import React from 'react';
import { useAppSelector } from 'soapbox/hooks';
import type { Attachment as AttachmentEntity } from 'soapbox/types/entities';
// import SensitiveButtonContainer from '../containers/sensitive_button_container';
import UploadProgress from '../components/upload-progress';
import UploadContainer from '../containers/upload_container';
const UploadForm = () => {
const mediaIds = useAppSelector((state) => state.compose.get('media_attachments').map((item: AttachmentEntity) => item.get('id')));
const classes = classNames('compose-form__uploads-wrapper', {
'contains-media': mediaIds.size !== 0,
});
return (
<div className='compose-form__upload-wrapper'>
<UploadProgress />
<div className={classes}>
{mediaIds.map((id: string) => (
<UploadContainer id={id} key={id} />
))}
</div>
{/* {!mediaIds.isEmpty() && <SensitiveButtonContainer />} */}
</div>
);
};
export default UploadForm;

Wyświetl plik

@ -1,43 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import { injectIntl, defineMessages } from 'react-intl';
import { length } from 'stringz';
import ProgressCircle from 'soapbox/components/progress_circle';
const messages = defineMessages({
title: { id: 'compose.character_counter.title', defaultMessage: 'Used {chars} out of {maxChars} characters' },
});
/**
* Renders a character counter
* @param {string} props.text - text to use to measure
* @param {number} props.max - max text allowed
*/
class VisualCharacterCounter extends React.PureComponent {
render() {
const { intl, text, max } = this.props;
const textLength = length(text);
const progress = textLength / max;
return (
<ProgressCircle
title={intl.formatMessage(messages.title, { chars: textLength, maxChars: max })}
progress={progress}
radius={10}
stroke={3}
/>
);
}
}
VisualCharacterCounter.propTypes = {
intl: PropTypes.object.isRequired,
text: PropTypes.string.isRequired,
max: PropTypes.number.isRequired,
};
export default injectIntl(VisualCharacterCounter);

Wyświetl plik

@ -0,0 +1,35 @@
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { length } from 'stringz';
import ProgressCircle from 'soapbox/components/progress_circle';
const messages = defineMessages({
title: { id: 'compose.character_counter.title', defaultMessage: 'Used {chars} out of {maxChars} characters' },
});
interface IVisualCharacterCounter {
/** max text allowed */
max: number,
/** text to use to measure */
text: string,
}
/** Renders a character counter */
const VisualCharacterCounter: React.FC<IVisualCharacterCounter> = ({ text, max }) => {
const intl = useIntl();
const textLength = length(text);
const progress = textLength / max;
return (
<ProgressCircle
title={intl.formatMessage(messages.title, { chars: textLength, maxChars: max })}
progress={progress}
radius={10}
stroke={3}
/>
);
};
export default VisualCharacterCounter;

Wyświetl plik

@ -1,16 +0,0 @@
import { connect } from 'react-redux';
import { makeGetAccount } from '../../../selectors';
import AutosuggestAccount from '../components/autosuggest_account';
const makeMapStateToProps = () => {
const getAccount = makeGetAccount();
const mapStateToProps = (state, { id }) => ({
account: getAccount(state, id),
});
return mapStateToProps;
};
export default connect(makeMapStateToProps)(AutosuggestAccount);

Wyświetl plik

@ -1,9 +0,0 @@
import { connect } from 'react-redux';
import UploadForm from '../components/upload_form';
const mapStateToProps = state => ({
mediaIds: state.getIn(['compose', 'media_attachments']).map(item => item.get('id')),
});
export default connect(mapStateToProps)(UploadForm);

Wyświetl plik

@ -2,7 +2,7 @@ import { urlRegex } from './url_regex';
const urlPlaceholder = 'xxxxxxxxxxxxxxxxxxxxxxx';
export function countableText(inputText) {
export function countableText(inputText: string) {
return inputText
.replace(urlRegex, urlPlaceholder)
.replace(/(^|[^\/\w])@(([a-z0-9_]+)@[a-z0-9\.\-]+[a-z0-9]+)/ig, '$1@$3');

Wyświetl plik

@ -1,7 +1,6 @@
const regexen = {};
const regexen: { [x: string]: string | RegExp } = {};
const regexSupplant = function(regex, flags) {
flags = flags || '';
const regexSupplant = function(regex: string | RegExp, flags = '') {
if (typeof regex !== 'string') {
if (regex.global && flags.indexOf('g') < 0) {
flags += 'g';
@ -24,7 +23,7 @@ const regexSupplant = function(regex, flags) {
}), flags);
};
const stringSupplant = function(str, values) {
const stringSupplant = function(str: string, values: { [x: string]: any; }) {
return str.replace(/#\{(\w+)\}/g, function(match, name) {
return values[name] || '';
});

Wyświetl plik

@ -1,59 +0,0 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import { defineMessages, injectIntl } from 'react-intl';
import DropdownMenu from 'soapbox/containers/dropdown_menu_container';
const messages = defineMessages({
collapse: { id: 'accordion.collapse', defaultMessage: 'Collapse' },
expand: { id: 'accordion.expand', defaultMessage: 'Expand' },
});
export default @injectIntl class Accordion extends React.PureComponent {
static propTypes = {
headline: PropTypes.node.isRequired,
children: PropTypes.oneOfType([PropTypes.string, PropTypes.element, PropTypes.node]),
menu: PropTypes.array,
expanded: PropTypes.bool,
onToggle: PropTypes.func,
intl: PropTypes.object.isRequired,
};
static defaultProps = {
expanded: false,
onToggle: () => {},
}
handleToggle = (e) => {
this.props.onToggle(!this.props.expanded);
e.preventDefault();
}
render() {
const { headline, children, menu, expanded, intl } = this.props;
return (
<div className={classNames('accordion', { 'accordion--expanded': expanded })}>
{menu && (
<div className='accordion__menu'>
<DropdownMenu items={menu} src={require('@tabler/icons/icons/dots-vertical.svg')} direction='right' />
</div>
)}
<button
type='button'
className='accordion__title'
onClick={this.handleToggle}
title={intl.formatMessage(expanded ? messages.collapse : messages.expand)}
>
{headline}
</button>
<div className='accordion__content'>
{children}
</div>
</div>
);
}
}

Wyświetl plik

@ -0,0 +1,52 @@
import classNames from 'classnames';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import DropdownMenu from 'soapbox/containers/dropdown_menu_container';
import type { Menu } from 'soapbox/components/dropdown_menu';
const messages = defineMessages({
collapse: { id: 'accordion.collapse', defaultMessage: 'Collapse' },
expand: { id: 'accordion.expand', defaultMessage: 'Expand' },
});
interface IAccordion {
headline: React.ReactNode,
children?: string | React.ReactNode,
menu?: Menu,
expanded?: boolean,
onToggle?: (value: boolean) => void,
}
const Accordion: React.FC<IAccordion> = ({ headline, children, menu, expanded = false, onToggle = () => {} }) => {
const intl = useIntl();
const handleToggle = (e: React.MouseEvent<HTMLButtonElement>) => {
onToggle(!expanded);
e.preventDefault();
};
return (
<div className={classNames('accordion', { 'accordion--expanded': expanded })}>
{menu && (
<div className='accordion__menu'>
<DropdownMenu items={menu} src={require('@tabler/icons/icons/dots-vertical.svg')} />
</div>
)}
<button
type='button'
className='accordion__title'
onClick={handleToggle}
title={intl.formatMessage(expanded ? messages.collapse : messages.expand)}
>
{headline}
</button>
<div className='accordion__content'>
{children}
</div>
</div>
);
};
export default Accordion;