diff options
Diffstat (limited to 'app/assets/javascripts/components/features/status')
5 files changed, 128 insertions, 5 deletions
diff --git a/app/assets/javascripts/components/features/status/components/action_bar.jsx b/app/assets/javascripts/components/features/status/components/action_bar.jsx index 030428440..3f8a0457d 100644 --- a/app/assets/javascripts/components/features/status/components/action_bar.jsx +++ b/app/assets/javascripts/components/features/status/components/action_bar.jsx @@ -61,8 +61,8 @@ const ActionBar = React.createClass({ <div style={{ background: '#2f3441', display: 'flex', flexDirection: 'row', borderTop: '1px solid #363c4b', borderBottom: '1px solid #363c4b', padding: '10px 0' }}> <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton title={intl.formatMessage(messages.reply)} icon='reply' onClick={this.handleReplyClick} /></div> <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton disabled={status.get('visibility') === 'private'} active={status.get('reblogged')} title={intl.formatMessage(messages.reblog)} icon={status.get('visibility') === 'private' ? 'lock' : 'retweet'} onClick={this.handleReblogClick} /></div> - <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div> - <div style={{ flex: '1 1 auto', textAlign: 'center' }}><DropdownMenu size={18} icon='ellipsis-h' items={menu} /></div> + <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton animate={true} active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div> + <div style={{ flex: '1 1 auto', textAlign: 'center' }}><DropdownMenu size={18} icon='ellipsis-h' items={menu} direction="left" /></div> </div> ); } diff --git a/app/assets/javascripts/components/features/status/components/card.jsx b/app/assets/javascripts/components/features/status/components/card.jsx new file mode 100644 index 000000000..ccb06dfd5 --- /dev/null +++ b/app/assets/javascripts/components/features/status/components/card.jsx @@ -0,0 +1,100 @@ +import PureRenderMixin from 'react-addons-pure-render-mixin'; +import ImmutablePropTypes from 'react-immutable-proptypes'; + +const outerStyle = { + display: 'flex', + cursor: 'pointer', + fontSize: '14px', + border: '1px solid #363c4b', + borderRadius: '4px', + color: '#616b86', + marginTop: '14px', + textDecoration: 'none', + overflow: 'hidden' +}; + +const contentStyle = { + flex: '1 1 auto', + padding: '8px', + paddingLeft: '14px', + overflow: 'hidden' +}; + +const titleStyle = { + display: 'block', + fontWeight: '500', + marginBottom: '5px', + color: '#d9e1e8', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap' +}; + +const descriptionStyle = { + color: '#d9e1e8' +}; + +const imageOuterStyle = { + flex: '0 0 100px', + background: '#373b4a' +}; + +const imageStyle = { + display: 'block', + width: '100%', + height: 'auto', + margin: '0', + borderRadius: '4px 0 0 4px' +}; + +const hostStyle = { + display: 'block', + marginTop: '5px', + fontSize: '13px' +}; + +const getHostname = url => { + const parser = document.createElement('a'); + parser.href = url; + return parser.hostname; +}; + +const Card = React.createClass({ + propTypes: { + card: ImmutablePropTypes.map + }, + + mixins: [PureRenderMixin], + + render () { + const { card } = this.props; + + if (card === null) { + return null; + } + + let image = ''; + + if (card.get('image')) { + image = ( + <div style={imageOuterStyle}> + <img src={card.get('image')} alt={card.get('title')} style={imageStyle} /> + </div> + ); + } + + return ( + <a style={outerStyle} href={card.get('url')} className='status-card'> + {image} + + <div style={contentStyle}> + <strong style={titleStyle} title={card.get('title')}>{card.get('title')}</strong> + <p style={descriptionStyle}>{card.get('description').substring(0, 50)}</p> + <span style={hostStyle}>{getHostname(card.get('url'))}</span> + </div> + </a> + ); + } +}); + +export default Card; diff --git a/app/assets/javascripts/components/features/status/components/detailed_status.jsx b/app/assets/javascripts/components/features/status/components/detailed_status.jsx index b967d966f..f2d6ae48a 100644 --- a/app/assets/javascripts/components/features/status/components/detailed_status.jsx +++ b/app/assets/javascripts/components/features/status/components/detailed_status.jsx @@ -7,6 +7,7 @@ import MediaGallery from '../../../components/media_gallery'; import VideoPlayer from '../../../components/video_player'; import { Link } from 'react-router'; import { FormattedDate, FormattedNumber } from 'react-intl'; +import CardContainer from '../containers/card_container'; const DetailedStatus = React.createClass({ @@ -32,7 +33,9 @@ const DetailedStatus = React.createClass({ render () { const status = this.props.status.get('reblog') ? this.props.status.get('reblog') : this.props.status; - let media = ''; + + let media = ''; + let applicationLink = ''; if (status.get('media_attachments').size > 0) { if (status.getIn(['media_attachments', 0, 'type']) === 'video') { @@ -40,6 +43,12 @@ const DetailedStatus = React.createClass({ } else { media = <MediaGallery sensitive={status.get('sensitive')} media={status.get('media_attachments')} height={300} onOpenMedia={this.props.onOpenMedia} />; } + } else { + media = <CardContainer statusId={status.get('id')} />; + } + + if (status.get('application')) { + applicationLink = <span> · <a className='detailed-status__application' style={{ color: 'inherit' }} href={status.getIn(['application', 'website'])} target='_blank' rel='nooopener'>{status.getIn(['application', 'name'])}</a></span>; } return ( @@ -54,7 +63,7 @@ const DetailedStatus = React.createClass({ {media} <div style={{ marginTop: '15px', color: '#616b86', fontSize: '14px', lineHeight: '18px' }}> - <a className='detailed-status__datetime' style={{ color: 'inherit' }} href={status.get('url')} target='_blank' rel='noopener'><FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' /></a> · <Link to={`/statuses/${status.get('id')}/reblogs`} style={{ color: 'inherit', textDecoration: 'none' }}><i className='fa fa-retweet' /><span style={{ fontWeight: '500', fontSize: '12px', marginLeft: '6px', display: 'inline-block' }}><FormattedNumber value={status.get('reblogs_count')} /></span></Link> · <Link to={`/statuses/${status.get('id')}/favourites`} style={{ color: 'inherit', textDecoration: 'none' }}><i className='fa fa-star' /><span style={{ fontWeight: '500', fontSize: '12px', marginLeft: '6px', display: 'inline-block' }}><FormattedNumber value={status.get('favourites_count')} /></span></Link> + <a className='detailed-status__datetime' style={{ color: 'inherit' }} href={status.get('url')} target='_blank' rel='noopener'><FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' /></a>{applicationLink} · <Link to={`/statuses/${status.get('id')}/reblogs`} style={{ color: 'inherit', textDecoration: 'none' }}><i className='fa fa-retweet' /><span style={{ fontWeight: '500', fontSize: '12px', marginLeft: '6px', display: 'inline-block' }}><FormattedNumber value={status.get('reblogs_count')} /></span></Link> · <Link to={`/statuses/${status.get('id')}/favourites`} style={{ color: 'inherit', textDecoration: 'none' }}><i className='fa fa-star' /><span style={{ fontWeight: '500', fontSize: '12px', marginLeft: '6px', display: 'inline-block' }}><FormattedNumber value={status.get('favourites_count')} /></span></Link> </div> </div> ); diff --git a/app/assets/javascripts/components/features/status/containers/card_container.jsx b/app/assets/javascripts/components/features/status/containers/card_container.jsx new file mode 100644 index 000000000..5c8bfeec2 --- /dev/null +++ b/app/assets/javascripts/components/features/status/containers/card_container.jsx @@ -0,0 +1,8 @@ +import { connect } from 'react-redux'; +import Card from '../components/card'; + +const mapStateToProps = (state, { statusId }) => ({ + card: state.getIn(['cards', statusId], null) +}); + +export default connect(mapStateToProps)(Card); diff --git a/app/assets/javascripts/components/features/status/index.jsx b/app/assets/javascripts/components/features/status/index.jsx index 0a1528fe9..389549849 100644 --- a/app/assets/javascripts/components/features/status/index.jsx +++ b/app/assets/javascripts/components/features/status/index.jsx @@ -23,6 +23,7 @@ import { ScrollContainer } from 'react-router-scroll'; import ColumnBackButton from '../../components/column_back_button'; import StatusContainer from '../../containers/status_container'; import { openMedia } from '../../actions/modal'; +import { isMobile } from '../../is_mobile' const makeMapStateToProps = () => { const getStatus = makeGetStatus(); @@ -47,7 +48,8 @@ const Status = React.createClass({ dispatch: React.PropTypes.func.isRequired, status: ImmutablePropTypes.map, ancestorsIds: ImmutablePropTypes.list, - descendantsIds: ImmutablePropTypes.list + descendantsIds: ImmutablePropTypes.list, + me: React.PropTypes.number }, mixins: [PureRenderMixin], @@ -80,6 +82,10 @@ const Status = React.createClass({ handleMentionClick (account) { this.props.dispatch(mentionCompose(account)); + + if (isMobile(window.innerWidth)) { + this.context.router.push('/statuses/new'); + } }, handleOpenMedia (url) { |