Updated components, style modules

This commit is contained in:
mgabdev
2019-08-13 11:54:29 -04:00
parent ecd081b5ed
commit c58d621daf
57 changed files with 1263 additions and 1205 deletions

View File

@@ -1,4 +1,5 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import detectPassiveEvents from 'detect-passive-events';
import Overlay from 'react-overlays/lib/Overlay';
import spring from 'react-motion/lib/spring';
@@ -159,7 +160,7 @@ class DropdownMenu extends PureComponent {
}
export default class Dropdown extends PureComponent {
export default class Dropdown extends ImmutablePureComponent {
static contextTypes = {
router: PropTypes.object,

View File

@@ -1,5 +1,6 @@
import classNames from 'classnames';
import './icon.scss';
export default class Icon extends PureComponent {
static propTypes = {

View File

@@ -1,4 +1,4 @@
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
import { injectIntl, defineMessages } from 'react-intl';
import classNames from 'classnames';
import Icon from '../icon';
@@ -44,7 +44,7 @@ class LoadMore extends PureComponent {
onClick={this.handleClick}
aria-label={intl.formatMessage(messages.load_more)}
>
{!gap && <FormattedMessage id='status.load_more' defaultMessage='Load more' />}
{!gap && intl.formatMessage(messages.load_more)}
{gap && <Icon id='ellipsis-h' />}
</button>
);

View File

@@ -1,4 +1,5 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { is } from 'immutable';
import { defineMessages, injectIntl } from 'react-intl';
import classNames from 'classnames';
@@ -15,7 +16,7 @@ const messages = defineMessages({
hidden: { id: 'status.media_hidden', defaultMessage: 'Media hidden' },
});
class Item extends PureComponent {
class Item extends ImmutablePureComponent {
static propTypes = {
attachment: ImmutablePropTypes.map.isRequired,

View File

@@ -1,11 +1,7 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Avatar from '../../avatar';
import ComposeFormContainer from '../../../features/compose/containers/compose_form_container';
import { openModal } from '../../../actions/modal';
import { cancelReplyCompose } from '../../../actions/compose';
import { me } from '../../../initial_state';
import ModalLayout from '../modal_layout';
const messages = defineMessages({
@@ -15,7 +11,6 @@ const messages = defineMessages({
const mapStateToProps = state => {
return {
account: state.getIn(['accounts', me]),
composeText: state.getIn(['compose', 'text']),
};
};
@@ -25,7 +20,6 @@ export default @connect(mapStateToProps)
class ComposeModal extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map,
intl: PropTypes.object.isRequired,
onClose: PropTypes.func.isRequired,
composeText: PropTypes.string,
@@ -49,16 +43,11 @@ class ComposeModal extends ImmutablePureComponent {
};
render () {
const { intl, account } = this.props;
const { intl } = this.props;
return (
<ModalLayout title={intl.formatMessage(messages.title)} onClose={onClickClose}>
<div className='timeline-compose-block'>
<div className='timeline-compose-block__avatar'>
<Avatar account={account} size={32} />
</div>
<ComposeFormContainer />
</div>
<TimelineComposeBlock />
</ModalLayout>
);
}

View File

@@ -24,4 +24,4 @@ export {
ReportModal,
UnauthorizedModal,
VideoModal,
}
};

View File

@@ -15,6 +15,7 @@ const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
previous: { id: 'lightbox.previous', defaultMessage: 'Previous' },
next: { id: 'lightbox.next', defaultMessage: 'Next' },
viewContext: { id: 'lightbox.view_context', defaultMessage: 'View context' },
});
export const previewState = 'previewMediaModal';
@@ -228,7 +229,9 @@ class MediaModal extends ImmutablePureComponent {
{status && (
<div className={classNames('media-modal__meta', { 'media-modal__meta--shifted': media.size > 1 })}>
<a href={status.get('url')} onClick={this.handleStatusClick}><FormattedMessage id='lightbox.view_context' defaultMessage='View context' /></a>
<a href={status.get('url')} onClick={this.handleStatusClick}>
{intl.formatMessage(messages.viewContext)}
</a>
</div>
)}

View File

@@ -1,10 +1,16 @@
import { injectIntl, FormattedMessage } from 'react-intl';
import { injectIntl, defineMessages } from 'react-intl';
import ToggleSwitch from '../../toggle_switch';
import Button from '../../button';
import { closeModal } from '../../../actions/modal';
import { muteAccount } from '../../../actions/accounts';
import { toggleHideNotifications } from '../../../actions/mutes';
const messages = defineMessages({
muteMessage: { id: 'confirmations.mute.message', defaultMessage: 'Are you sure you want to mute {name}?' },
hideNotifications: { id: 'mute_modal.hide_notifications', defaultMessage: 'Hide notifications from this user?' },
cancel: { id: 'confirmation_modal.cancel', defaultMessage: 'Cancel' },
confirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' },
});
const mapStateToProps = state => {
return {
@@ -72,15 +78,11 @@ class MuteModal extends PureComponent {
<div className='modal-root__modal mute-modal'>
<div className='mute-modal__container'>
<p>
<FormattedMessage
id='confirmations.mute.message'
defaultMessage='Are you sure you want to mute {name}?'
values={{ name: <strong>@{account.get('acct')}</strong> }}
/>
{intl.formatMessage(messages.muteMessage, { name: <strong>@{account.get('acct')}</strong> })}
</p>
<div>
<label htmlFor='mute-modal__hide-notifications-checkbox'>
<FormattedMessage id='mute_modal.hide_notifications' defaultMessage='Hide notifications from this user?' />
{intl.formatMessage(messages.hideNotifications)}
{' '}
<ToggleSwitch id='mute-modal__hide-notifications-checkbox' checked={notifications} onChange={this.toggleNotifications} />
</label>
@@ -89,10 +91,10 @@ class MuteModal extends PureComponent {
<div className='mute-modal__action-bar'>
<Button onClick={this.handleCancel} className='mute-modal__cancel-button'>
<FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
{intl.formatMessage(messages.cancel)}
</Button>
<Button onClick={this.handleClick} ref={this.setRef}>
<FormattedMessage id='confirmations.mute.confirm' defaultMessage='Mute' />
{intl.formatMessage(messages.confirm)}
</Button>
</div>
</div>

View File

@@ -1,5 +1,5 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import { defineMessages, injectIntl } from 'react-intl';
import { OrderedSet } from 'immutable';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ToggleSwitch from '../../toggle_switch';
@@ -14,6 +14,10 @@ const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
placeholder: { id: 'report.placeholder', defaultMessage: 'Additional comments' },
submit: { id: 'report.submit', defaultMessage: 'Submit' },
hint: { id: 'report.hint', defaultMessage: 'The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:' },
forwardHint: { id: 'report.forward_hint', defaultMessage: 'The account is from another server. Send an anonymized copy of the report there as well?' },
forward: { id: 'report.forward', defaultMessage: 'Forward to {target}' },
target: { id: 'report.target', defaultMessage: 'Report {target}' },
});
const makeMapStateToProps = () => {
@@ -89,12 +93,14 @@ class ReportModal extends ImmutablePureComponent {
<div className='modal-root__modal report-modal'>
<div className='report-modal__target'>
<IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={16} />
<FormattedMessage id='report.target' defaultMessage='Report {target}' values={{ target: <strong>{account.get('acct')}</strong> }} />
{intl.formatMessage(messages.target, {
target: <strong>{account.get('acct')}</strong>
})}
</div>
<div className='report-modal__container'>
<div className='report-modal__comment'>
<p><FormattedMessage id='report.hint' defaultMessage='The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:' /></p>
<p>{intl.formatMessage(messages.hint)}</p>
<textarea
className='setting-text light'
@@ -108,11 +114,15 @@ class ReportModal extends ImmutablePureComponent {
{domain && (
<div>
<p><FormattedMessage id='report.forward_hint' defaultMessage='The account is from another server. Send an anonymized copy of the report there as well?' /></p>
<p>{intl.formatMessage(messages.forwardHint)}</p>
<div className='setting-toggle'>
<ToggleSwitch id='report-forward' checked={forward} disabled={isSubmitting} onChange={this.handleForwardChange} />
<label htmlFor='report-forward' className='setting-toggle__label'><FormattedMessage id='report.forward' defaultMessage='Forward to {target}' values={{ target: domain }} /></label>
<label htmlFor='report-forward' className='setting-toggle__label'>
{intl.formatMessage(messages.forward, {
target: domain
})}
</label>
</div>
</div>
)}

View File

@@ -2,7 +2,6 @@ import Base from '../modal_base';
import Bundle from '../../features/ui/util/bundle';
import BundleModalError from '../bundle_modal_error';
import {
ModalLoading,
ActionsModal,
MediaModal,
VideoModal,
@@ -14,6 +13,8 @@ import {
UnauthorizedModal,
} from '../modal';
import ModalLoading from '../modal_loading';
import {
MuteModal,
ReportModal,

View File

@@ -18,6 +18,8 @@ const mapStateToProps = (state, { pollId }) => ({
const messages = defineMessages({
closed: { id: 'poll.closed', defaultMessage: 'Closed' },
vote: { id: 'poll.vote', defaultMessage: 'Vote' },
refresh: { id: 'poll.refresh', defaultMessage: 'Refresh' },
});
const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
@@ -149,14 +151,14 @@ class Poll extends ImmutablePureComponent {
{
!showResults &&
<Button className='poll__button' disabled={disabled} onClick={this.handleVote} secondary>
<FormattedMessage id='poll.vote' defaultMessage='Vote' />
{intl.formatMessage(messages.vote)}
</Button>
}
{
showResults && !this.props.disabled &&
<span>
<button className='poll__link' onClick={this.handleRefresh}>
<FormattedMessage id='poll.refresh' defaultMessage='Refresh' />
{intl.formatMessage(messages.refresh)}
</button>
&nbsp;·&nbsp;
</span>

View File

@@ -0,0 +1 @@
export { default } from './search';

View File

@@ -1,7 +1,10 @@
import classNames from 'classnames';
import Overlay from 'react-overlays/lib/Overlay';
import Icon from '../icon';
import SearchPopout from '../search_popout';
import './search.scss';
export default class Search extends PureComponent {
static contextTypes = {
@@ -11,44 +14,22 @@ export default class Search extends PureComponent {
static propTypes = {
value: PropTypes.string.isRequired,
submitted: PropTypes.bool,
onChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
onClear: PropTypes.func.isRequired,
onShow: PropTypes.func.isRequired,
openInRoute: PropTypes.bool,
intl: PropTypes.object.isRequired,
placeholder: PropTypes.string.isRequired,
className: PropTypes.string,
searchTitle: PropTypes.string,
onChange: PropTypes.func.isRequired,
onKeyUp: PropTypes.func.isRequired,
handleSubmit: PropTypes.func,
withOverlay: PropTypes.bool,
handleClear: PropTypes.func.isRequired,
};
state = {
expanded: false,
};
handleChange = (e) => {
this.props.onChange(e.target.value);
}
handleClear = (e) => {
e.preventDefault();
if (this.props.value.length > 0 || this.props.submitted) {
this.props.onClear();
}
}
handleKeyUp = (e) => {
if (e.key === 'Enter') {
e.preventDefault();
this.props.onSubmit();
if (this.props.openInRoute) {
this.context.router.history.push('/search');
}
} else if (e.key === 'Escape') {
document.querySelector('.ui').parentElement.focus();
}
}
handleFocus = () => {
this.setState({ expanded: true });
this.props.onShow();
@@ -59,32 +40,46 @@ export default class Search extends PureComponent {
}
render() {
const { intl, value, submitted } = this.props;
const { value, submitted, placeholder, className, searchTitle, onKeyUp, handleClear, handleSubmit, withOverlay, onChange } = this.props;
const { expanded } = this.state;
const hasValue = value.length > 0 || submitted;
const classes = classNames('search', className);
const iconClass = hasValue ? 'active' : '';
return (
<div className='search'>
<div className={classes}>
<label>
<span style={{ display: 'none' }}>{intl.formatMessage(messages.placeholder)}</span>
<span className='invisible'>{placeholder}</span>
<input
className='search__input'
type='text'
placeholder={intl.formatMessage(messages.placeholder)}
placeholder={placeholder}
value={value}
onChange={this.handleChange}
onKeyUp={this.handleKeyUp}
onChange={onChange}
onKeyUp={onKeyUp}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
/>
</label>
<div role='button' tabIndex='0' className='search__icon' onClick={this.handleClear}>
<Icon id='search' className={hasValue ? '' : 'active'} />
<Icon id='times-circle' className={hasValue ? 'active' : ''} aria-label={intl.formatMessage(messages.placeholder)} />
<div role='button' tabIndex='0' className='search__icon' onClick={handleClear}>
<Icon id='search' className={iconClass} />
<Icon id='times-circle' className={iconClass} aria-label={placeholder} />
</div>
<Overlay show={expanded && !hasValue} placement='bottom' target={this}>
<SearchPopout />
</Overlay>
{
withOverlay &&
<Overlay show={expanded && !hasValue} placement='bottom' target={this}>
<SearchPopout />
</Overlay>
}
{
(searchTitle && handleSubmit) &&
<Button onClick={handleSubmit}>{intl.formatMessage(messages.searchTitle)}</Button>
}
</div>
);
}

View File

@@ -12,15 +12,16 @@ class SectionHeadlineBarItem extends PureComponent {
PropTypes.string,
PropTypes.node,
]),
exact: PropTypes.bool,
};
render() {
const { to, title, icon, className, onClick } = this.props;
const { to, title, icon, className, onClick, exact } = this.props;
const classes = classNames('section-header-bar__item', className);
if (to) {
return (<NavLink className={classes} to={to}>{title}</NavLink>);
return (<NavLink className={classes} exact={exact} to={to}>{title}</NavLink>);
} else if (icon) {
<button className={classes} onClick={onClick} title={title}>
<Icon id={icon} fixedWidth />
@@ -33,14 +34,17 @@ class SectionHeadlineBarItem extends PureComponent {
export default class SectionHeadlineBar extends PureComponent {
static propTypes = {
items: PropTypes.array,
items: PropTypes.array.isRequired,
className: PropTypes.string,
};
render() {
const { items } = this.props;
const { items, className } = this.props;
const classes = classNames('section-headline-bar', className);
return (
<div className='section-headline-bar'>
<div className={classes}>
{
items.forEach(item, i => (
<SectionHeadlineBarItem key={`shbi-{i}`} {...item} />

View File

@@ -1,9 +1,10 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ToggleSwitch from '../toggle_switch';
import './setting_toggle.scss';
export default class SettingToggle extends PureComponent {
export default class SettingToggle extends ImmutablePureComponent {
static propTypes = {
prefix: PropTypes.string,

View File

@@ -10,7 +10,7 @@ import RelativeTimestamp from '../relative_timestamp';
import DisplayName from '../display_name';
import StatusContent from '../status_content/status_content';
import StatusActionBar from '../status_action_bar/status_action_bar';
import Card from '../../features/status/components/card';
import Card from '../../features/status/components/card/card';
import { MediaGallery, Video } from '../../features/ui/util/async-components';
import Icon from '../icon';
import Poll from '../../components/poll';

View File

@@ -1,4 +1,5 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { Set as ImmutableSet } from 'immutable';
import noop from 'lodash/noop';
import StatusContent from '../status_content';
@@ -21,7 +22,7 @@ const mapDispatchToProps = (dispatch, { id }) => ({
});
export default @connect(mapStateToProps, mapDispatchToProps)
class StatusCheckBox extends PureComponent {
class StatusCheckBox extends ImmutablePureComponent {
static propTypes = {
status: ImmutablePropTypes.map.isRequired,

View File

@@ -1,4 +1,5 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { FormattedMessage } from 'react-intl';
import classnames from 'classnames';
import { isRtl } from '../../utils/rtl';
@@ -9,7 +10,7 @@ import './status_content.scss';
const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
export default class StatusContent extends PureComponent {
export default class StatusContent extends ImmutablePureComponent {
static contextTypes = {
router: PropTypes.object,

View File

@@ -0,0 +1 @@
export { default } from './timeline_compose_block';

View File

@@ -0,0 +1,40 @@
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Avatar from '../avatar';
import ComposeFormContainer from '../../features/compose/containers/compose_form_container';
import { me } from '../../initial_state';
import './timeline_compose_block.scss';
const mapStateToProps = state => {
return {
account: state.getIn(['accounts', me]),
};
};
export default @connect(mapStateToProps)
class TimelineComposeBlock extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map.isRequired,
size: PropTypes.number,
}
static defaultProps = {
size: 32,
}
render() {
const { account, size, ...rest } = this.props;
return (
<div className='timeline-compose-block'>
<div className='timeline-compose-block__avatar'>
<Avatar account={account} size={size} />
</div>
<ComposeFormContainer {...rest} />
</div>
)
}
}

View File

@@ -0,0 +1,19 @@
.timeline-compose-block {
display: flex;
align-items: flex-start;
padding: 20px;
margin-bottom: 20px;
@include gab-container-standards();
.emoji-picker-wrapper {
.emoji-picker-dropdown {
top: 10px;
}
}
.compose-form {
flex: 1 1;
padding: 0 0 0 20px !important;
position: relative;
}
}