diff options
Diffstat (limited to 'app/javascript/glitch/components')
15 files changed, 175 insertions, 267 deletions
diff --git a/app/javascript/glitch/components/account/header.js b/app/javascript/glitch/components/account/header.js index b79140c02..bc2ce30f6 100644 --- a/app/javascript/glitch/components/account/header.js +++ b/app/javascript/glitch/components/account/header.js @@ -44,7 +44,6 @@ Imports: import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; -import escapeTextContentForBrowser from 'escape-html'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; @@ -89,7 +88,7 @@ export default class AccountHeader extends ImmutablePureComponent { static propTypes = { account : ImmutablePropTypes.map, - me : PropTypes.number.isRequired, + me : PropTypes.string.isRequired, onFollow : PropTypes.func.isRequired, intl : PropTypes.object.isRequired, }; @@ -117,7 +116,7 @@ then we set the `displayName` to just be the `username` of the account. return null; } - let displayName = account.get('display_name'); + let displayName = account.get('display_name_html'); let info = ''; let actionBtn = ''; let following = false; @@ -167,16 +166,11 @@ appropriate icon. } /* - -`displayNameHTML` processes the `displayName` and prepares it for -insertion into the document. Meanwhile, we extract the `text` and + we extract the `text` and `metadata` from our account's `note` using `processBio()`. */ - const displayNameHTML = { - __html : emojify(escapeTextContentForBrowser(displayName)), - }; const { text, metadata } = processBio(account.get('note')); /* @@ -194,15 +188,11 @@ Here, we render our component using all the things we've defined above. <div> <a href={account.get('url')} target='_blank' rel='noopener'> <span className='account__header__avatar'> - <Avatar - src={account.get('avatar')} - staticSrc={account.get('avatar_static')} - size={90} - /> + <Avatar account={account} size={90} /> </span> <span className='account__header__display-name' - dangerouslySetInnerHTML={displayNameHTML} + dangerouslySetInnerHTML={{ __html: displayName }} /> </a> <span className='account__header__username'> diff --git a/app/javascript/glitch/components/local_settings/navigation/item/style.scss b/app/javascript/glitch/components/local_settings/navigation/item/style.scss index 505c86912..33d7d3744 100644 --- a/app/javascript/glitch/components/local_settings/navigation/item/style.scss +++ b/app/javascript/glitch/components/local_settings/navigation/item/style.scss @@ -1,4 +1,4 @@ -@import 'variables'; +@import 'styles/variables'; .glitch.local-settings__navigation__item { display: block; diff --git a/app/javascript/glitch/components/local_settings/navigation/style.scss b/app/javascript/glitch/components/local_settings/navigation/style.scss index 1cc39e3e9..a610a1212 100644 --- a/app/javascript/glitch/components/local_settings/navigation/style.scss +++ b/app/javascript/glitch/components/local_settings/navigation/style.scss @@ -1,4 +1,4 @@ -@import 'variables'; +@import 'styles/variables'; .glitch.local-settings__navigation { background: $primary-text-color; diff --git a/app/javascript/glitch/components/local_settings/page/index.js b/app/javascript/glitch/components/local_settings/page/index.js index cb041c0b8..338d86333 100644 --- a/app/javascript/glitch/components/local_settings/page/index.js +++ b/app/javascript/glitch/components/local_settings/page/index.js @@ -16,6 +16,7 @@ const messages = defineMessages({ layout_auto: { id: 'layout.auto', defaultMessage: 'Auto' }, layout_desktop: { id: 'layout.desktop', defaultMessage: 'Desktop' }, layout_mobile: { id: 'layout.single', defaultMessage: 'Mobile' }, + side_arm_none: { id: 'settings.side_arm.none', defaultMessage: 'None' }, }); @injectIntl @@ -61,6 +62,24 @@ export default class LocalSettingsPage extends React.PureComponent { > <FormattedMessage id='settings.navbar_under' defaultMessage='Navbar at the bottom (Mobile only)' /> </LocalSettingsPageItem> + <section> + <h2><FormattedMessage id='settings.compose_box_opts' defaultMessage='Compose box options' /></h2> + <LocalSettingsPageItem + settings={settings} + item={['side_arm']} + id='mastodon-settings--side_arm' + options={[ + { value: 'none', message: intl.formatMessage(messages.side_arm_none) }, + { value: 'direct', message: intl.formatMessage({ id: 'privacy.direct.short' }) }, + { value: 'private', message: intl.formatMessage({ id: 'privacy.private.short' }) }, + { value: 'unlisted', message: intl.formatMessage({ id: 'privacy.unlisted.short' }) }, + { value: 'public', message: intl.formatMessage({ id: 'privacy.public.short' }) }, + ]} + onChange={onChange} + > + <FormattedMessage id='settings.side_arm' defaultMessage='Secondary toot button:' /> + </LocalSettingsPageItem> + </section> </div> ), ({ onChange, settings }) => ( diff --git a/app/javascript/glitch/components/local_settings/page/item/style.scss b/app/javascript/glitch/components/local_settings/page/item/style.scss index e614030c0..da1941b99 100644 --- a/app/javascript/glitch/components/local_settings/page/item/style.scss +++ b/app/javascript/glitch/components/local_settings/page/item/style.scss @@ -1,4 +1,4 @@ -@import 'variables'; +@import 'styles/variables'; .glitch.local-settings__page__item { select { diff --git a/app/javascript/glitch/components/local_settings/page/style.scss b/app/javascript/glitch/components/local_settings/page/style.scss index 7269056c3..53c95ea40 100644 --- a/app/javascript/glitch/components/local_settings/page/style.scss +++ b/app/javascript/glitch/components/local_settings/page/style.scss @@ -1,4 +1,4 @@ -@import 'variables'; +@import 'styles/variables'; .glitch.local-settings__page { display: block; diff --git a/app/javascript/glitch/components/local_settings/style.scss b/app/javascript/glitch/components/local_settings/style.scss index 6f7fcbaa4..54fec47bd 100644 --- a/app/javascript/glitch/components/local_settings/style.scss +++ b/app/javascript/glitch/components/local_settings/style.scss @@ -1,4 +1,4 @@ -@import 'variables'; +@import 'styles/variables'; .glitch.local-settings { position: relative; diff --git a/app/javascript/glitch/components/notification/follow.js b/app/javascript/glitch/components/notification/follow.js index d340e83c8..e2c21bf35 100644 --- a/app/javascript/glitch/components/notification/follow.js +++ b/app/javascript/glitch/components/notification/follow.js @@ -1,106 +1,54 @@ -/* +// `<NotificationFollow>` +// ====================== -`<NotificationFollow>` -====================== +// * * * * * * * // -This component renders a follow notification. +// Imports +// ------- -__Props:__ - - - __`id` (`PropTypes.number.isRequired`) :__ - This is the id of the notification. - - - __`onDeleteNotification` (`PropTypes.func.isRequired`) :__ - The function to call when a notification should be - dismissed/deleted. - - - __`account` (`PropTypes.object.isRequired`) :__ - The account associated with the follow notification, ie the account - which followed the user. - - - __`intl` (`PropTypes.object.isRequired`) :__ - Our internationalization object, inserted by `@injectIntl`. - -*/ - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -/* - -Imports: --------- - -*/ - -// Package imports // +// Package imports. import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; -import escapeTextContentForBrowser from 'escape-html'; import ImmutablePureComponent from 'react-immutable-pure-component'; -// Mastodon imports // -import emojify from '../../../mastodon/emoji'; +// Mastodon imports. import Permalink from '../../../mastodon/components/permalink'; import AccountContainer from '../../../mastodon/containers/account_container'; -// Our imports // +// Our imports. import NotificationOverlayContainer from '../notification/overlay/container'; -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -/* +// * * * * * * * // -Implementation: ---------------- - -*/ +// Implementation +// -------------- export default class NotificationFollow extends ImmutablePureComponent { static propTypes = { - id : PropTypes.number.isRequired, + id : PropTypes.string.isRequired, account : ImmutablePropTypes.map.isRequired, notification : ImmutablePropTypes.map.isRequired, }; -/* - -### `render()` - -This actually renders the component. - -*/ - render () { const { account, notification } = this.props; -/* - -`link` is a container for the account's `displayName`, which links to -the account timeline using a `<Permalink>`. - -*/ - - const displayName = account.get('display_name') || account.get('username'); - const displayNameHTML = { __html: emojify(escapeTextContentForBrowser(displayName)) }; + // Links to the display name. + const displayName = account.get('display_name_html') || account.get('username'); const link = ( <Permalink className='notification__display-name' href={account.get('url')} title={account.get('acct')} to={`/accounts/${account.get('id')}`} - dangerouslySetInnerHTML={displayNameHTML} + dangerouslySetInnerHTML={{ __html: displayName }} /> ); -/* - -We can now render our component. - -*/ - + // Renders. return ( <div className='notification notification-follow'> <div className='notification__message'> diff --git a/app/javascript/glitch/components/status/action_bar.js b/app/javascript/glitch/components/status/action_bar.js index 7c73002c1..f4450d31b 100644 --- a/app/javascript/glitch/components/status/action_bar.js +++ b/app/javascript/glitch/components/status/action_bar.js @@ -8,7 +8,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; // Mastodon imports // import RelativeTimestamp from '../../../mastodon/components/relative_timestamp'; import IconButton from '../../../mastodon/components/icon_button'; -import DropdownMenu from '../../../mastodon/components/dropdown_menu'; +import DropdownMenuContainer from '../../../mastodon/containers/dropdown_menu_container'; const messages = defineMessages({ delete: { id: 'status.delete', defaultMessage: 'Delete' }, @@ -16,6 +16,7 @@ const messages = defineMessages({ mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' }, block: { id: 'account.block', defaultMessage: 'Block @{name}' }, reply: { id: 'status.reply', defaultMessage: 'Reply' }, + share: { id: 'status.share', defaultMessage: 'Share' }, replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' }, reblog: { id: 'status.reblog', defaultMessage: 'Boost' }, cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' }, @@ -24,6 +25,9 @@ const messages = defineMessages({ report: { id: 'status.report', defaultMessage: 'Report @{name}' }, muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' }, unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' }, + pin: { id: 'status.pin', defaultMessage: 'Pin on profile' }, + unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' }, + embed: { id: 'status.embed', defaultMessage: 'Embed' }, }); @injectIntl @@ -43,8 +47,10 @@ export default class StatusActionBar extends ImmutablePureComponent { onMute: PropTypes.func, onBlock: PropTypes.func, onReport: PropTypes.func, + onEmbed: PropTypes.func, onMuteConversation: PropTypes.func, - me: PropTypes.number, + onPin: PropTypes.func, + me: PropTypes.string, withDismiss: PropTypes.bool, intl: PropTypes.object.isRequired, }; @@ -61,6 +67,13 @@ export default class StatusActionBar extends ImmutablePureComponent { this.props.onReply(this.props.status, this.context.router.history); } + handleShareClick = () => { + navigator.share({ + text: this.props.status.get('search_index'), + url: this.props.status.get('url'), + }); + } + handleFavouriteClick = () => { this.props.onFavourite(this.props.status); } @@ -73,6 +86,10 @@ export default class StatusActionBar extends ImmutablePureComponent { this.props.onDelete(this.props.status); } + handlePinClick = () => { + this.props.onPin(this.props.status); + } + handleMentionClick = () => { this.props.onMention(this.props.status.get('account'), this.context.router.history); } @@ -89,6 +106,10 @@ export default class StatusActionBar extends ImmutablePureComponent { this.context.router.history.push(`/statuses/${this.props.status.get('id')}`); } + handleEmbed = () => { + this.props.onEmbed(this.props.status); + } + handleReport = () => { this.props.onReport(this.props.status); } @@ -99,9 +120,10 @@ export default class StatusActionBar extends ImmutablePureComponent { render () { const { status, me, intl, withDismiss } = this.props; - const reblogDisabled = status.get('visibility') === 'private' || status.get('visibility') === 'direct'; + const mutingConversation = status.get('muted'); const anonymousAccess = !me; + const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')); let menu = []; let reblogIcon = 'retweet'; @@ -109,14 +131,23 @@ export default class StatusActionBar extends ImmutablePureComponent { let replyTitle; menu.push({ text: intl.formatMessage(messages.open), action: this.handleOpen }); + + if (publicStatus) { + menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed }); + } + menu.push(null); - if (withDismiss) { + if (status.getIn(['account', 'id']) === me || withDismiss) { menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick }); menu.push(null); } if (status.getIn(['account', 'id']) === me) { + if (publicStatus) { + menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick }); + } + menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick }); } else { menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick }); @@ -126,14 +157,6 @@ export default class StatusActionBar extends ImmutablePureComponent { menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport }); } - /* - if (status.get('visibility') === 'direct') { - reblogIcon = 'envelope'; - } else if (status.get('visibility') === 'private') { - reblogIcon = 'lock'; - } - */ - if (status.get('in_reply_to_id', null) === null) { replyIcon = 'reply'; replyTitle = intl.formatMessage(messages.reply); @@ -142,14 +165,19 @@ export default class StatusActionBar extends ImmutablePureComponent { replyTitle = intl.formatMessage(messages.replyAll); } + const shareButton = ('share' in navigator) && status.get('visibility') === 'public' && ( + <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} /> + ); + return ( <div className='status__action-bar'> <IconButton className='status__action-bar-button' disabled={anonymousAccess} title={replyTitle} icon={replyIcon} onClick={this.handleReplyClick} /> - <IconButton className='status__action-bar-button' disabled={anonymousAccess || reblogDisabled} active={status.get('reblogged')} title={reblogDisabled ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} /> - <IconButton className='status__action-bar-button star-icon' disabled={anonymousAccess} animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /> + <IconButton className='status__action-bar-button' disabled={anonymousAccess || !publicStatus} active={status.get('reblogged')} pressed={status.get('reblogged')} title={!publicStatus ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} /> + <IconButton className='status__action-bar-button star-icon' disabled={anonymousAccess} animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /> + {shareButton} <div className='status__action-bar-dropdown'> - <DropdownMenu items={menu} disabled={anonymousAccess} icon='ellipsis-h' size={18} direction='right' ariaLabel='More' /> + <DropdownMenuContainer disabled={anonymousAccess} status={status} items={menu} icon='ellipsis-h' size={18} direction='right' ariaLabel='More' /> </div> <a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener'><RelativeTimestamp timestamp={status.get('created_at')} /></a> diff --git a/app/javascript/glitch/components/status/container.js b/app/javascript/glitch/components/status/container.js index 1d572e0e7..da2771c0b 100644 --- a/app/javascript/glitch/components/status/container.js +++ b/app/javascript/glitch/components/status/container.js @@ -38,11 +38,11 @@ import { favourite, unreblog, unfavourite, + pin, + unpin, } from '../../../mastodon/actions/interactions'; -import { - blockAccount, - muteAccount, -} from '../../../mastodon/actions/accounts'; +import { blockAccount } from '../../../mastodon/actions/accounts'; +import { initMuteModal } from '../../../mastodon/actions/mutes'; import { muteStatus, unmuteStatus, @@ -80,10 +80,6 @@ const messages = defineMessages({ id : 'confirmations.block.confirm', defaultMessage : 'Block', }, - muteConfirm : { - id : 'confirmations.mute.confirm', - defaultMessage : 'Mute', - }, }); /* * * * */ @@ -193,6 +189,18 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ } }, + onPin (status) { + if (status.get('pinned')) { + dispatch(unpin(status)); + } else { + dispatch(pin(status)); + } + }, + + onEmbed (status) { + dispatch(openModal('EMBED', { url: status.get('url') })); + }, + onDelete (status) { if (!this.deleteModal) { dispatch(deleteStatus(status.get('id'))); @@ -230,11 +238,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ }, onMute (account) { - dispatch(openModal('CONFIRM', { - message: <FormattedMessage id='confirmations.mute.message' defaultMessage='Are you sure you want to mute {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />, - confirm: intl.formatMessage(messages.muteConfirm), - onConfirm: () => dispatch(muteAccount(account.get('id'))), - })); + dispatch(initMuteModal(account)); }, onMuteConversation (status) { diff --git a/app/javascript/glitch/components/status/content.js b/app/javascript/glitch/components/status/content.js index 06fe04ce0..06015619b 100644 --- a/app/javascript/glitch/components/status/content.js +++ b/app/javascript/glitch/components/status/content.js @@ -1,13 +1,11 @@ // Package imports // import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import escapeTextContentForBrowser from 'escape-html'; import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import classnames from 'classnames'; // Mastodon imports // -import emojify from '../../../mastodon/emoji'; import { isRtl } from '../../../mastodon/rtl'; import Permalink from '../../../mastodon/components/permalink'; @@ -32,7 +30,7 @@ export default class StatusContent extends React.PureComponent { const node = this.node; const links = node.querySelectorAll('a'); - for (var i = 0; i < links.length; ++i) { + for (let i = 0; i < links.length; ++i) { let link = links[i]; let mention = this.props.status.get('mentions').find(item => link.href === item.get('url')); @@ -131,12 +129,8 @@ export default class StatusContent extends React.PureComponent { this.state.hidden ); - const content = { __html: emojify(status.get('content')) }; - const spoilerContent = { - __html: emojify(escapeTextContentForBrowser( - status.get('spoiler_text', '') - )), - }; + const content = { __html: status.get('contentHtml') }; + const spoilerContent = { __html: status.get('spoilerHtml') }; const directionStyle = { direction: 'ltr' }; const classNames = classnames('status__content', { 'status__content--with-action': parseClick && !disabled, @@ -188,7 +182,7 @@ export default class StatusContent extends React.PureComponent { } return ( - <div className={classNames} ref={this.setRef}> + <div className={classNames}> <p style={{ marginBottom: hidden && status.get('mentions').isEmpty() ? '0px' : null }} onMouseDown={this.handleMouseDown} @@ -205,6 +199,7 @@ export default class StatusContent extends React.PureComponent { <div className={`status__content__spoiler ${!hidden ? 'status__content__spoiler--visible' : ''}`}> <div + ref={this.setRef} style={directionStyle} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} @@ -218,11 +213,11 @@ export default class StatusContent extends React.PureComponent { } else if (parseClick) { return ( <div - ref={this.setRef} className={classNames} style={directionStyle} > <div + ref={this.setRef} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} dangerouslySetInnerHTML={content} @@ -233,11 +228,10 @@ export default class StatusContent extends React.PureComponent { } else { return ( <div - ref={this.setRef} className='status__content' style={directionStyle} > - <div dangerouslySetInnerHTML={content} /> + <div ref={this.setRef} dangerouslySetInnerHTML={content} /> {media} </div> ); diff --git a/app/javascript/glitch/components/status/gallery/item.js b/app/javascript/glitch/components/status/gallery/item.js index d646825a3..ab4aab8dc 100644 --- a/app/javascript/glitch/components/status/gallery/item.js +++ b/app/javascript/glitch/components/status/gallery/item.js @@ -17,6 +17,24 @@ export default class StatusGalleryItem extends React.PureComponent { autoPlayGif: PropTypes.bool.isRequired, }; + handleMouseEnter = (e) => { + if (this.hoverToPlay()) { + e.target.play(); + } + } + + handleMouseLeave = (e) => { + if (this.hoverToPlay()) { + e.target.pause(); + e.target.currentTime = 0; + } + } + + hoverToPlay () { + const { attachment, autoPlayGif } = this.props; + return !autoPlayGif && attachment.get('type') === 'gifv'; + } + handleClick = (e) => { const { index, onClick } = this.props; @@ -112,6 +130,8 @@ export default class StatusGalleryItem extends React.PureComponent { role='application' src={attachment.get('url')} onClick={this.handleClick} + onMouseEnter={this.handleMouseEnter} + onMouseLeave={this.handleMouseLeave} autoPlay={autoPlay} loop muted diff --git a/app/javascript/glitch/components/status/header.js b/app/javascript/glitch/components/status/header.js index 5ce59fba4..f741950b1 100644 --- a/app/javascript/glitch/components/status/header.js +++ b/app/javascript/glitch/components/status/header.js @@ -9,41 +9,30 @@ component for better documentation and maintainance by */ - /* * * * */ +// * * * * * * * // -/* - -Imports: --------- +// Imports +// ------- -*/ - -// Package imports // +// Package imports. import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { defineMessages, injectIntl } from 'react-intl'; -// Mastodon imports // +// Mastodon imports. import Avatar from '../../../mastodon/components/avatar'; import AvatarOverlay from '../../../mastodon/components/avatar_overlay'; import DisplayName from '../../../mastodon/components/display_name'; import IconButton from '../../../mastodon/components/icon_button'; import VisibilityIcon from './visibility_icon'; - /* * * * */ - -/* - -Inital setup: -------------- +// * * * * * * * // -The `messages` constant is used to define any messages that we need -from inside props. In our case, these are the `collapse` and -`uncollapse` messages used with our collapse/uncollapse buttons. - -*/ +// Initial setup +// ------------- +// Messages for use with internationalization stuff. const messages = defineMessages({ collapse: { id: 'status.collapse', defaultMessage: 'Collapse' }, uncollapse: { id: 'status.uncollapse', defaultMessage: 'Uncollapse' }, @@ -53,43 +42,10 @@ const messages = defineMessages({ direct: { id: 'privacy.direct.short', defaultMessage: 'Direct' }, }); - /* * * * */ - -/* - -The `<StatusHeader>` component: -------------------------------- - -The `<StatusHeader>` component wraps together the header information -(avatar, display name) and upper buttons and icons (collapsing, media -icons) into a single `<header>` element. - -### Props - - - __`account`, `friend` (`ImmutablePropTypes.map`) :__ - These give the accounts associated with the status. `account` is - the author of the post; `friend` will have their avatar appear - in the overlay if provided. - - - __`mediaIcon` (`PropTypes.string`) :__ - If a mediaIcon should be placed in the header, this string - specifies it. - - - __`collapsible`, `collapsed` (`PropTypes.bool`) :__ - These props tell whether a post can be, and is, collapsed. - - - __`parseClick` (`PropTypes.func`) :__ - This function will be called when the user clicks inside the header - information. - - - __`setExpansion` (`PropTypes.func`) :__ - This function is used to set the expansion state of the post. - - - __`intl` (`PropTypes.object`) :__ - This is our internationalization object, provided by - `injectIntl()`. +// * * * * * * * // -*/ +// The component +// ------------- @injectIntl export default class StatusHeader extends React.PureComponent { @@ -105,18 +61,7 @@ export default class StatusHeader extends React.PureComponent { intl: PropTypes.object.isRequired, }; -/* - -### Implementation - -#### `handleCollapsedClick()`. - -`handleCollapsedClick()` is just a simple callback for our collapsing -button. It calls `setExpansion` to set the collapsed state of the -status. - -*/ - + // Handles clicks on collapsed button handleCollapsedClick = (e) => { const { collapsed, setExpansion } = this.props; if (e.button === 0) { @@ -125,29 +70,13 @@ status. } } -/* - -#### `handleAccountClick()`. - -`handleAccountClick()` handles any clicks on the header info. It calls -`parseClick()` with our `account` as the anticipatory `destination`. - -*/ - + // Handles clicks on account name/image handleAccountClick = (e) => { const { status, parseClick } = this.props; parseClick(e, `/accounts/${+status.getIn(['account', 'id'])}`); } -/* - -#### `render()`. - -`render()` actually puts our element on the screen. `<StatusHeader>` -has a very straightforward rendering process. - -*/ - + // Rendering. render () { const { status, @@ -162,16 +91,28 @@ has a very straightforward rendering process. return ( <header className='status__info'> - { - -/* - -We have to include the status icons before the header content because -it is rendered as a float. - -*/ - - } + <a + href={account.get('url')} + target='_blank' + className='status__avatar' + onClick={this.handleAccountClick} + > + { + friend ? ( + <AvatarOverlay account={account} friend={friend} /> + ) : ( + <Avatar account={account} size={48} /> + ) + } + </a> + <a + href={account.get('url')} + target='_blank' + className='status__display-name' + onClick={this.handleAccountClick} + > + <DisplayName account={account} /> + </a> <div className='status__info__icons'> {mediaIcon ? ( <i @@ -197,39 +138,6 @@ it is rendered as a float. /> ) : null} </div> - { - -/* - -This begins our header content. It is all wrapped inside of a link -which gets handled by `handleAccountClick`. We use an `<AvatarOverlay>` -if we have a `friend` and a normal `<Avatar>` if we don't. - -*/ - - } - <a - href={account.get('url')} - target='_blank' - className='status__display-name' - onClick={this.handleAccountClick} - > - <div className='status__avatar'>{ - friend ? ( - <AvatarOverlay - staticSrc={account.get('avatar_static')} - overlaySrc={friend.get('avatar_static')} - /> - ) : ( - <Avatar - src={account.get('avatar')} - staticSrc={account.get('avatar_static')} - size={48} - /> - ) - }</div> - <DisplayName account={account} /> - </a> </header> ); diff --git a/app/javascript/glitch/components/status/index.js b/app/javascript/glitch/components/status/index.js index 55e6f1876..9e758793c 100644 --- a/app/javascript/glitch/components/status/index.js +++ b/app/javascript/glitch/components/status/index.js @@ -155,20 +155,23 @@ export default class Status extends ImmutablePureComponent { }; static propTypes = { - id : PropTypes.number, + id : PropTypes.string, status : ImmutablePropTypes.map, account : ImmutablePropTypes.map, settings : ImmutablePropTypes.map, notification : ImmutablePropTypes.map, - me : PropTypes.number, + me : PropTypes.string, onFavourite : PropTypes.func, onReblog : PropTypes.func, onModalReblog : PropTypes.func, onDelete : PropTypes.func, + onPin : PropTypes.func, onMention : PropTypes.func, onMute : PropTypes.func, onMuteConversation : PropTypes.func, onBlock : PropTypes.func, + onEmbed : PropTypes.func, + onHeightChange : PropTypes.func, onReport : PropTypes.func, onOpenMedia : PropTypes.func, onOpenVideo : PropTypes.func, diff --git a/app/javascript/glitch/components/status/prepend.js b/app/javascript/glitch/components/status/prepend.js index 6213e4c8d..8c0aed0f4 100644 --- a/app/javascript/glitch/components/status/prepend.js +++ b/app/javascript/glitch/components/status/prepend.js @@ -22,12 +22,8 @@ Imports: import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import escapeTextContentForBrowser from 'escape-html'; import { FormattedMessage } from 'react-intl'; -// Mastodon imports // -import emojify from '../../../mastodon/emoji'; - /* * * * */ /* @@ -99,9 +95,7 @@ generate the message. > <b dangerouslySetInnerHTML={{ - __html : emojify(escapeTextContentForBrowser( - account.get('display_name') || account.get('username') - )), + __html : account.get('display_name_html') || account.get('username'), }} /> </a> |