diff --git a/app/javascript/fonts/montserrat/montserrat-extra-bold-800.eot b/app/javascript/fonts/montserrat/montserrat-extra-bold-800.eot deleted file mode 100644 index 85c4c6f7..00000000 Binary files a/app/javascript/fonts/montserrat/montserrat-extra-bold-800.eot and /dev/null differ diff --git a/app/javascript/fonts/montserrat/montserrat-extra-bold-800.svg b/app/javascript/fonts/montserrat/montserrat-extra-bold-800.svg deleted file mode 100644 index 350e53f5..00000000 --- a/app/javascript/fonts/montserrat/montserrat-extra-bold-800.svg +++ /dev/null @@ -1,327 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/javascript/fonts/montserrat/montserrat-extra-bold-800.ttf b/app/javascript/fonts/montserrat/montserrat-extra-bold-800.ttf deleted file mode 100644 index 94514b21..00000000 Binary files a/app/javascript/fonts/montserrat/montserrat-extra-bold-800.ttf and /dev/null differ diff --git a/app/javascript/fonts/montserrat/montserrat-extra-bold-800.woff b/app/javascript/fonts/montserrat/montserrat-extra-bold-800.woff deleted file mode 100644 index f236d6c9..00000000 Binary files a/app/javascript/fonts/montserrat/montserrat-extra-bold-800.woff and /dev/null differ diff --git a/app/javascript/fonts/montserrat/montserrat-extra-bold-800.woff2 b/app/javascript/fonts/montserrat/montserrat-extra-bold-800.woff2 deleted file mode 100644 index 88710763..00000000 Binary files a/app/javascript/fonts/montserrat/montserrat-extra-bold-800.woff2 and /dev/null differ diff --git a/app/javascript/gabsocial/actions/notifications.js b/app/javascript/gabsocial/actions/notifications.js index 7b4607ac..6ea1baf8 100644 --- a/app/javascript/gabsocial/actions/notifications.js +++ b/app/javascript/gabsocial/actions/notifications.js @@ -30,7 +30,7 @@ export const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR'; export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP'; export const NOTIFICATIONS_MARK_READ = 'NOTIFICATIONS_MARK_READ'; -export const MAX_QUEUED_NOTIFICATIONS = 40; +export const MAX_QUEUED_NOTIFICATIONS = 40 defineMessages({ mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' }, @@ -43,12 +43,12 @@ const fetchRelatedRelationships = (dispatch, notifications) => { if (accountIds.length > 0) { dispatch(fetchRelationships(accountIds)); } -}; +} export function initializeNotifications() { return { type: NOTIFICATIONS_INITIALIZE, - }; + } } export function updateNotifications(notification, intlMessages, intlLocale) { diff --git a/app/javascript/gabsocial/components/avatar.js b/app/javascript/gabsocial/components/avatar.js index 4b9a72de..50fba04b 100644 --- a/app/javascript/gabsocial/components/avatar.js +++ b/app/javascript/gabsocial/components/avatar.js @@ -40,7 +40,7 @@ class Avatar extends ImmutablePureComponent { const shouldAnimate = animate || !sameImg const options = { - className: [_s.default, _s.circle].join(' '), + className: [_s.default, _s.circle, _s.overflowHidden].join(' '), onMouseEnter: shouldAnimate ? this.handleMouseEnter : undefined, onMouseLeave: shouldAnimate ? this.handleMouseLeave : undefined, src: account.get((hovering || animate) ? 'avatar' : 'avatar_static'), diff --git a/app/javascript/gabsocial/components/badge.js b/app/javascript/gabsocial/components/badge.js index 1838afbb..51429fe6 100644 --- a/app/javascript/gabsocial/components/badge.js +++ b/app/javascript/gabsocial/components/badge.js @@ -20,7 +20,7 @@ export default class Badge extends PureComponent { render() { const { children, description } = this.props - const { hovering } = this.state + const { hovering } = this.state // : todo : tooltip return ( + + + ) + } + +} diff --git a/app/javascript/gabsocial/components/display_name.js b/app/javascript/gabsocial/components/display_name.js index 41b55b06..50ee5d82 100644 --- a/app/javascript/gabsocial/components/display_name.js +++ b/app/javascript/gabsocial/components/display_name.js @@ -28,6 +28,7 @@ class DisplayName extends ImmutablePureComponent { multiline: PropTypes.bool, large: PropTypes.bool, noHover: PropTypes.bool, + noUsername: PropTypes.bool, } handleMouseEnter = debounce(() => { @@ -41,7 +42,13 @@ class DisplayName extends ImmutablePureComponent { } render() { - const { account, multiline, large, noHover } = this.props + const { + account, + multiline, + large, + noHover, + noUsername + } = this.props if (!account) return null @@ -114,9 +121,12 @@ class DisplayName extends ImmutablePureComponent { */ } - - @{account.get('acct')} - + { + !noUsername && + + @{account.get('acct')} + + } ) } diff --git a/app/javascript/gabsocial/components/panel/notification_filter_panel.js b/app/javascript/gabsocial/components/panel/notification_filter_panel.js new file mode 100644 index 00000000..ac7d866e --- /dev/null +++ b/app/javascript/gabsocial/components/panel/notification_filter_panel.js @@ -0,0 +1,40 @@ +import { Fragment } from 'react' +import { defineMessages, injectIntl } from 'react-intl' +import ImmutablePureComponent from 'react-immutable-pure-component' +import ImmutablePropTypes from 'react-immutable-proptypes' +import { shortNumberFormat } from '../../utils/numbers' +import PanelLayout from './panel_layout' +import Button from '../button' +import Divider from '../divider' +import Heading from '../heading' +import Icon from '../icon' +import Text from '../text' + +const messages = defineMessages({ + title: { id: 'notification_filters', defaultMessage: 'Notification Filters' }, +}) + +export default +@injectIntl +class NotificationFilterPanel extends ImmutablePureComponent { + + static propTypes = { + intl: PropTypes.object.isRequired, + } + + render() { + const { intl } = this.props + + // date + // verfied or not + // specific user + // specific status + // only people i do/not follow + + return ( + + + + ) + } +} \ No newline at end of file diff --git a/app/javascript/gabsocial/components/popover/status_options_popover.js b/app/javascript/gabsocial/components/popover/status_options_popover.js index 432e3a6c..1d756b91 100644 --- a/app/javascript/gabsocial/components/popover/status_options_popover.js +++ b/app/javascript/gabsocial/components/popover/status_options_popover.js @@ -1,5 +1,39 @@ export default class StatusOptionsPopover extends PureComponent { render() { + + // if (publicStatus) { + // menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy }); + // menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed }); + // menu.push(null); + // } + + // if (me === status.getIn(['account', 'id'])) { + // if (publicStatus) { + // menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick }); + // } else { + // if (status.get('visibility') === 'private') { + // menu.push({ text: intl.formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog_private), action: this.handleReblogClick }); + // } + // } + + // menu.push(null); + // menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick }); + // menu.push(null); + // menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick }); + // menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick }); + // } else { + // menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick }); + // menu.push(null); + // menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick }); + // menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick }); + // menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport }); + // if (isStaff) { + // menu.push(null); + // menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` }); + // menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` }); + // } + // } + return (
{ /* */ } diff --git a/app/javascript/gabsocial/components/scrollable_list.js b/app/javascript/gabsocial/components/scrollable_list.js index 3306ef75..60dc5ac5 100644 --- a/app/javascript/gabsocial/components/scrollable_list.js +++ b/app/javascript/gabsocial/components/scrollable_list.js @@ -1,17 +1,17 @@ -import { throttle } from 'lodash'; -import { List as ImmutableList } from 'immutable'; -import IntersectionObserverArticleContainer from '../containers/intersection_observer_article_container'; -import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper'; -import ColumnIndicator from './column_indicator'; -import LoadMore from './load_more'; +import { throttle } from 'lodash' +import { List as ImmutableList } from 'immutable' +import IntersectionObserverArticle from './intersection_observer_article' +import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper' +import ColumnIndicator from './column_indicator' +import LoadMore from './load_more' -const MOUSE_IDLE_DELAY = 300; +const MOUSE_IDLE_DELAY = 300 export default class ScrollableList extends PureComponent { static contextTypes = { router: PropTypes.object, - }; + } static propTypes = { scrollKey: PropTypes.string.isRequired, @@ -23,11 +23,11 @@ export default class ScrollableList extends PureComponent { children: PropTypes.node, onScrollToTop: PropTypes.func, onScroll: PropTypes.func, - }; + } state = { cachedMediaWidth: 250, // Default media/card width using default Gab Social theme - }; + } intersectionObserverWrapper = new IntersectionObserverWrapper(); @@ -213,7 +213,7 @@ export default class ScrollableList extends PureComponent {
{React.Children.map(this.props.children, (child, index) => ( - + ))} {loadMore} diff --git a/app/javascript/gabsocial/components/status/status.js b/app/javascript/gabsocial/components/status/status.js index 373e8d79..c088d9c1 100644 --- a/app/javascript/gabsocial/components/status/status.js +++ b/app/javascript/gabsocial/components/status/status.js @@ -272,9 +272,9 @@ class Status extends ImmutablePureComponent { render() { let media = null; - let statusAvatar, prepend, rebloggedByText, reblogContent; + let prepend, rebloggedByText, reblogContent; - const { intl, hidden, featured, otherAccounts, unread, showThread, group, promoted } = this.props; + const { intl, hidden, featured, unread, showThread, group, promoted } = this.props; // console.log("replies:", this.props.replies) @@ -321,7 +321,7 @@ class Status extends ImmutablePureComponent { prepend = (
; + media = } else if (status.get('media_attachments').size > 0) { if (status.getIn(['media_attachments', 0, 'type']) === 'video') { const video = status.getIn(['media_attachments', 0]); @@ -375,6 +375,7 @@ class Status extends ImmutablePureComponent { {Component => ( )} - ); + ) } else { media = ( @@ -408,10 +408,10 @@ class Status extends ImmutablePureComponent { /> )} - ); + ) } } else if (status.get('spoiler_text').length === 0 && status.get('card')) { - console.log("card:", status.get('card')) + // console.log("card:", status.get('card')) media = ( - ); + ) } - const handlers = this.props.muted - ? {} - : { - reply: this.handleHotkeyReply, - favourite: this.handleHotkeyFavourite, - boost: this.handleHotkeyBoost, - mention: this.handleHotkeyMention, - open: this.handleHotkeyOpen, - openProfile: this.handleHotkeyOpenProfile, - moveUp: this.handleHotkeyMoveUp, - moveDown: this.handleHotkeyMoveDown, - toggleHidden: this.handleHotkeyToggleHidden, - toggleSensitive: this.handleHotkeyToggleSensitive, - }; + const handlers = this.props.muted ? {} : { + reply: this.handleHotkeyReply, + favourite: this.handleHotkeyFavourite, + boost: this.handleHotkeyBoost, + mention: this.handleHotkeyMention, + open: this.handleHotkeyOpen, + openProfile: this.handleHotkeyOpenProfile, + moveUp: this.handleHotkeyMoveUp, + moveDown: this.handleHotkeyMoveDown, + toggleHidden: this.handleHotkeyToggleHidden, + toggleSensitive: this.handleHotkeyToggleSensitive, + } const statusUrl = `/${status.getIn(['account', 'acct'])}/posts/${status.get('id')}`; diff --git a/app/javascript/gabsocial/containers/compose_container.js b/app/javascript/gabsocial/containers/compose_container.js deleted file mode 100644 index 5de350f0..00000000 --- a/app/javascript/gabsocial/containers/compose_container.js +++ /dev/null @@ -1,39 +0,0 @@ -import { Provider } from 'react-redux'; -import { IntlProvider, addLocaleData } from 'react-intl'; -import { getLocale } from '../locales'; -import configureStore from '../store/configureStore'; -import { hydrateStore } from '../actions/store'; -import { fetchCustomEmojis } from '../actions/custom_emojis'; -import initialState from '../initial_state'; -import Compose from '../features/standalone/compose'; - -const { localeData, messages } = getLocale(); -addLocaleData(localeData); - -const store = configureStore(); - -if (initialState) { - store.dispatch(hydrateStore(initialState)); -} - -store.dispatch(fetchCustomEmojis()); - -export default class TimelineContainer extends PureComponent { - - static propTypes = { - locale: PropTypes.string.isRequired, - }; - - render () { - const { locale } = this.props; - - return ( - - - - - - ); - } - -} diff --git a/app/javascript/gabsocial/containers/intersection_observer_article_container.js b/app/javascript/gabsocial/containers/intersection_observer_article_container.js deleted file mode 100644 index 6ab487bf..00000000 --- a/app/javascript/gabsocial/containers/intersection_observer_article_container.js +++ /dev/null @@ -1,16 +0,0 @@ -import { setHeight } from '../actions/height_cache'; -import IntersectionObserverArticle from '../components/intersection_observer_article'; - -const makeMapStateToProps = (state, props) => ({ - cachedHeight: state.getIn(['height_cache', props.saveHeightKey, props.id]), -}); - -const mapDispatchToProps = (dispatch) => ({ - - onHeightChange (key, id, height) { - dispatch(setHeight(key, id, height)); - }, - -}); - -export default connect(makeMapStateToProps, mapDispatchToProps)(IntersectionObserverArticle); diff --git a/app/javascript/gabsocial/containers/timeline_container.js b/app/javascript/gabsocial/containers/timeline_container.js deleted file mode 100644 index ec406d3b..00000000 --- a/app/javascript/gabsocial/containers/timeline_container.js +++ /dev/null @@ -1,55 +0,0 @@ -import { Fragment } from 'react'; -import ReactDOM from 'react-dom'; -import { Provider } from 'react-redux'; -import { IntlProvider, addLocaleData } from 'react-intl'; -import { getLocale } from '../locales'; -import configureStore from '../store/configureStore'; -import { hydrateStore } from '../actions/store'; -import initialState from '../initial_state'; -import PublicTimeline from '../features/standalone/public_timeline'; -import HashtagTimeline from '../features/standalone/hashtag_timeline'; -import ModalRoot from '../components/modal/modal_root' - -const { localeData, messages } = getLocale(); -addLocaleData(localeData); - -const store = configureStore(); - -if (initialState) { - store.dispatch(hydrateStore(initialState)); -} - -export default class TimelineContainer extends PureComponent { - - static propTypes = { - locale: PropTypes.string.isRequired, - hashtag: PropTypes.string, - local: PropTypes.bool, - }; - - static defaultProps = { - local: !initialState.settings.known_fediverse, - }; - - render () { - const { locale, hashtag, local } = this.props; - - const timeline = hashtag ? : ; - - return ( - - - - {timeline} - - {ReactDOM.createPortal( - , - document.getElementById('modal-container'), - )} - - - - ); - } - -} diff --git a/app/javascript/gabsocial/features/account_gallery/account_gallery.js b/app/javascript/gabsocial/features/account_gallery/account_gallery.js index df39efde..583763a5 100644 --- a/app/javascript/gabsocial/features/account_gallery/account_gallery.js +++ b/app/javascript/gabsocial/features/account_gallery/account_gallery.js @@ -20,7 +20,7 @@ const messages = defineMessages({ error: { id: 'empty_column.account_unavailable', defaultMessage: 'Profile unavailable' }, }); -const mapStateToProps = (state, { params: { username } }) => { +const mapStateToProps = (state, { mediaType, params: { username } }) => { const accounts = state.getIn(['accounts']); const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() == username.toLowerCase()); @@ -67,7 +67,7 @@ class LoadMoreMedia extends ImmutablePureComponent { disabled={this.props.disabled} onClick={this.handleLoadMore} /> - ); + ) } } @@ -86,11 +86,11 @@ class AccountGallery extends ImmutablePureComponent { isAccount: PropTypes.bool, unavailable: PropTypes.bool, intl: PropTypes.object.isRequired, - }; + } state = { width: 323, - }; + } componentDidMount() { const { params: { username }, accountId } = this.props; @@ -158,27 +158,29 @@ class AccountGallery extends ImmutablePureComponent { const { width } = this.state; if (!isAccount && accountId !== -1) { - return (); + return } else if (accountId === -1 || (!attachments && isLoading)) { - return (); + return } else if (unavailable) { - return (); + return } - let loadOlder = null; + let loadOlder = null if (hasMore && !(isLoading && attachments.size === 0)) { - loadOlder = ; + loadOlder = } return (
- {attachments.map((attachment, index) => attachment === null ? ( - 0 ? attachments.getIn(index - 1, 'id') : null} onLoadMore={this.handleLoadMore} /> - ) : ( + { + attachments.map((attachment, index) => attachment === null ? ( + 0 ? attachments.getIn(index - 1, 'id') : null} onLoadMore={this.handleLoadMore} /> + ) : ( - ))} + )) + } { attachments.size == 0 && @@ -190,11 +192,12 @@ class AccountGallery extends ImmutablePureComponent { {loadOlder}
- {isLoading && attachments.size === 0 && ( + { + isLoading && attachments.size === 0 &&
- )} + }
); } diff --git a/app/javascript/gabsocial/features/account_timeline/components/inner_header/inner_header.js b/app/javascript/gabsocial/features/account_timeline/components/inner_header/inner_header.js index aeebf159..1ede04f4 100644 --- a/app/javascript/gabsocial/features/account_timeline/components/inner_header/inner_header.js +++ b/app/javascript/gabsocial/features/account_timeline/components/inner_header/inner_header.js @@ -308,7 +308,7 @@ class Header extends ImmutablePureComponent { }} /> } - + {/**/}
} diff --git a/app/javascript/gabsocial/features/community_timeline/community_timeline.js b/app/javascript/gabsocial/features/community_timeline/community_timeline.js index ef341368..c0944003 100644 --- a/app/javascript/gabsocial/features/community_timeline/community_timeline.js +++ b/app/javascript/gabsocial/features/community_timeline/community_timeline.js @@ -23,7 +23,6 @@ const mapStateToProps = state => { timelineId, allFediverse, onlyMedia, - // hasUnread: state.getIn(['timelines', `${timelineId}${onlyMedia ? ':media' : ''}`, 'unread']) > 0, } } @@ -39,7 +38,6 @@ class CommunityTimeline extends PureComponent { static propTypes = { dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, - // hasUnread: PropTypes.bool, onlyMedia: PropTypes.bool, allFediverse: PropTypes.bool, timelineId: PropTypes.string, diff --git a/app/javascript/gabsocial/features/compose/components/action_bar/action_bar.js b/app/javascript/gabsocial/features/compose/components/action_bar/action_bar.js index fbbd6d07..82fff08d 100644 --- a/app/javascript/gabsocial/features/compose/components/action_bar/action_bar.js +++ b/app/javascript/gabsocial/features/compose/components/action_bar/action_bar.js @@ -52,7 +52,7 @@ class ActionBar extends PureComponent { return (
- + { /* */ }
); diff --git a/app/javascript/gabsocial/features/favorites/favorites.js b/app/javascript/gabsocial/features/favorites/favorites.js new file mode 100644 index 00000000..2f80fd10 --- /dev/null +++ b/app/javascript/gabsocial/features/favorites/favorites.js @@ -0,0 +1,70 @@ +import ImmutablePureComponent from 'react-immutable-pure-component'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import { FormattedMessage } from 'react-intl'; +import { fetchReblogs } from '../../actions/interactions'; +import { fetchStatus } from '../../actions/statuses'; +import { makeGetStatus } from '../../selectors'; +import AccountContainer from '../../containers/account_container'; +import ColumnIndicator from '../../components/column_indicator'; +import ScrollableList from '../../components/scrollable_list'; + +const mapStateToProps = (state, props) => { + const getStatus = makeGetStatus(); + const status = getStatus(state, { + id: props.params.statusId, + username: props.params.username, + }); + + return { + status, + accountIds: state.getIn(['user_lists', 'favorites', props.params.statusId]), + }; +}; + +export default +@connect(mapStateToProps) +class Favorites extends ImmutablePureComponent { + + static propTypes = { + params: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + accountIds: ImmutablePropTypes.list, + status: ImmutablePropTypes.map, + }; + + componentWillMount() { + this.props.dispatch(fetchReblogs(this.props.params.statusId)); + this.props.dispatch(fetchStatus(this.props.params.statusId)); + } + + componentWillReceiveProps(nextProps) { + if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { + this.props.dispatch(fetchReblogs(nextProps.params.statusId)); + this.props.dispatch(fetchStatus(nextProps.params.statusId)); + } + } + + render() { + const { accountIds, status } = this.props; + + if (!accountIds) { + return + } else if (!status) { + return + } + + return ( + } + > + { + accountIds.map(id => + + ) + } + + ); + } + +} diff --git a/app/javascript/gabsocial/features/favorites/index.js b/app/javascript/gabsocial/features/favorites/index.js new file mode 100644 index 00000000..fe8f1099 --- /dev/null +++ b/app/javascript/gabsocial/features/favorites/index.js @@ -0,0 +1 @@ +export { default } from './favorites' \ No newline at end of file diff --git a/app/javascript/gabsocial/features/group_members/group_members.js b/app/javascript/gabsocial/features/group_members/group_members.js index ea6a8a84..72fb43ed 100644 --- a/app/javascript/gabsocial/features/group_members/group_members.js +++ b/app/javascript/gabsocial/features/group_members/group_members.js @@ -72,7 +72,10 @@ class GroupMembers extends ImmutablePureComponent { return (
true} /> - {menu.length > 0 && } + { /* + menu.length > 0 && + */ + }
); })} diff --git a/app/javascript/gabsocial/features/groups/timeline/components/header.js b/app/javascript/gabsocial/features/groups/timeline/components/header.js index 47c2cc61..3a27e3e2 100644 --- a/app/javascript/gabsocial/features/groups/timeline/components/header.js +++ b/app/javascript/gabsocial/features/groups/timeline/components/header.js @@ -45,7 +45,8 @@ getActionButton() { { text: intl.formatMessage(messages.removed_accounts), to: `/groups/${group.get('id')}/removed_accounts` }, ]; - return ; + // ; + return
} render () { diff --git a/app/javascript/gabsocial/features/hashtag_timeline/hashtag_timeline.js b/app/javascript/gabsocial/features/hashtag_timeline/hashtag_timeline.js index 907eb307..f5b8df6d 100644 --- a/app/javascript/gabsocial/features/hashtag_timeline/hashtag_timeline.js +++ b/app/javascript/gabsocial/features/hashtag_timeline/hashtag_timeline.js @@ -1,12 +1,12 @@ -import { FormattedMessage } from 'react-intl'; -import { isEqual } from 'lodash'; -import { expandHashtagTimeline, clearTimeline } from '../../actions/timelines'; -import { connectHashtagStream } from '../../actions/streaming'; -import StatusListContainer from '../../containers/status_list_container'; +import { FormattedMessage } from 'react-intl' +import { isEqual } from 'lodash' +import { expandHashtagTimeline, clearTimeline } from '../../actions/timelines' +import { connectHashtagStream } from '../../actions/streaming' +import StatusListContainer from '../../containers/status_list_container' const mapStateToProps = (state, props) => ({ hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0, -}); +}) export default @connect(mapStateToProps) @@ -18,88 +18,114 @@ class HashtagTimeline extends PureComponent { params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, hasUnread: PropTypes.bool, - }; + } title = () => { - let title = [this.props.params.id]; + let title = [this.props.params.id] if (this.additionalFor('any')) { - title.push(' ', ); + title.push(' ', + + ) } if (this.additionalFor('all')) { - title.push(' ', ); + title.push(' ', + + ) } if (this.additionalFor('none')) { - title.push(' ', ); + title.push(' ', + + ) } - return title; + return title } additionalFor = (mode) => { - const { tags } = this.props.params; + const { tags } = this.props.params try { - return tags[mode].map(tag => tag.value).join('/'); + return tags[mode].map(tag => tag.value).join('/') } catch (error) { - return ''; + return '' } } _subscribe (dispatch, id, tags = {}) { - let any = (tags.any || []).map(tag => tag.value); - let all = (tags.all || []).map(tag => tag.value); + let any = (tags.any || []).map(tag => tag.value) + let all = (tags.all || []).map(tag => tag.value) let none = (tags.none || []).map(tag => tag.value); [id, ...any].map(tag => { this.disconnects.push(dispatch(connectHashtagStream(id, tag, status => { - let tags = status.tags.map(tag => tag.name); + let tags = status.tags.map(tag => tag.name) return all.filter(tag => tags.includes(tag)).length === all.length && - none.filter(tag => tags.includes(tag)).length === 0; - }))); - }); + none.filter(tag => tags.includes(tag)).length === 0 + }))) + }) } _unsubscribe () { - this.disconnects.map(disconnect => disconnect()); - this.disconnects = []; + this.disconnects.map(disconnect => disconnect()) + this.disconnects = [] } componentDidMount () { - const { dispatch } = this.props; - const { id, tags } = this.props.params; + const { dispatch } = this.props + const { id, tags } = this.props.params - this._subscribe(dispatch, id, tags); - dispatch(expandHashtagTimeline(id, { tags })); + this._subscribe(dispatch, id, tags) + dispatch(expandHashtagTimeline(id, { tags })) } componentWillReceiveProps (nextProps) { - const { dispatch, params } = this.props; - const { id, tags } = nextProps.params; + const { dispatch, params } = this.props + const { id, tags } = nextProps.params if (id !== params.id || !isEqual(tags, params.tags)) { - this._unsubscribe(); - this._subscribe(dispatch, id, tags); - this.props.dispatch(clearTimeline(`hashtag:${id}`)); - this.props.dispatch(expandHashtagTimeline(id, { tags })); + this._unsubscribe() + this._subscribe(dispatch, id, tags) + this.props.dispatch(clearTimeline(`hashtag:${id}`)) + this.props.dispatch(expandHashtagTimeline(id, { tags })) } } componentWillUnmount () { - this._unsubscribe(); + this._unsubscribe() } handleLoadMore = maxId => { - const { id, tags } = this.props.params; - this.props.dispatch(expandHashtagTimeline(id, { maxId, tags })); + const { id, tags } = this.props.params + this.props.dispatch(expandHashtagTimeline(id, { maxId, tags })) } render () { - const { hasUnread } = this.props; - const { id } = this.props.params; + const { id } = this.props.params return ( { const output = [message] @@ -33,18 +40,115 @@ class Notification extends ImmutablePureComponent { renderFavorite = () => { const { status, notificationType, accounts } = this.props + return ( +
+
+
+ + + +
+
+ { + accounts.slice(0, 6).map((account, i) => ( + + + + )) + } +
+
+
+
+ { + accounts.slice(0, 1).map((account, i) => ( + + )) + } +
+ +  and 3 others favorited your gab + +
+
+ +
+ + post this at 1-14-2020 12:15pm (edited) + +
+
+ +
+
+
+ ) } render() { - const { notification } = this.props - const account = notification.get('account') + const { + status, + notificationType, + accounts, + intl + } = this.props - switch (notification.get('type')) { - case 'favourite': - return this.renderFavorite() - } + // const linkTo = '/admin/posts/123/reblogs' // etc. - return null + return ( + +
+
+ + + +
+
+ { + accounts.slice(0, 6).map((account, i) => ( + + + + )) + } +
+
+
+
+ { + accounts.slice(0, 1).map((account, i) => ( + + )) + } +
+ +  and 3 others favorited your gab + +
+
+ +
+ + post this at 1-14-2020 12:15pm (edited) + +
+
+ +
+
+
+ ) } } diff --git a/app/javascript/gabsocial/features/notifications/containers/notification_container.js b/app/javascript/gabsocial/features/notifications/containers/notification_container.js index 456e8bdf..aca7b28f 100644 --- a/app/javascript/gabsocial/features/notifications/containers/notification_container.js +++ b/app/javascript/gabsocial/features/notifications/containers/notification_container.js @@ -1,70 +1,74 @@ -import { openModal } from '../../../actions/modal'; -import { mentionCompose } from '../../../actions/compose'; +import { openModal } from '../../../actions/modal' +import { mentionCompose } from '../../../actions/compose' import { reblog, favourite, unreblog, unfavourite, -} from '../../../actions/interactions'; +} from '../../../actions/interactions' import { hideStatus, revealStatus, -} from '../../../actions/statuses'; -import { boostModal } from '../../../initial_state'; -import { makeGetNotification, makeGetStatus } from '../../../selectors'; -import Notification from '../components/notification/notification'; +} from '../../../actions/statuses' +import { boostModal, me } from '../../../initial_state' +import { makeGetNotification, makeGetStatus } from '../../../selectors' +import Notification from '../components/notification/notification-alt' const makeMapStateToProps = () => { - const getNotification = makeGetNotification(); - const getStatus = makeGetStatus(); + const getNotification = makeGetNotification() + const getStatus = makeGetStatus() const mapStateToProps = (state, props) => { - const notification = getNotification(state, props.notification, props.accountId); + const notification = getNotification(state, props.notification, props.accountId) + + const account = state.getIn(['accounts', me]) + return { + accounts: [account, account, account], notification: notification, status: notification.get('status') ? getStatus(state, { id: notification.get('status') }) : null, - }; - }; + } + } - return mapStateToProps; -}; + return mapStateToProps +} const mapDispatchToProps = dispatch => ({ onMention: (account, router) => { - dispatch(mentionCompose(account, router)); + dispatch(mentionCompose(account, router)) }, onModalReblog (status) { - dispatch(reblog(status)); + dispatch(reblog(status)) }, onReblog (status, e) { if (status.get('reblogged')) { - dispatch(unreblog(status)); + dispatch(unreblog(status)) } else { if (e.shiftKey || !boostModal) { - this.onModalReblog(status); + this.onModalReblog(status) } else { - dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog })); + dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog })) } } }, onFavourite (status) { if (status.get('favourited')) { - dispatch(unfavourite(status)); + dispatch(unfavourite(status)) } else { - dispatch(favourite(status)); + dispatch(favourite(status)) } }, onToggleHidden (status) { if (status.get('hidden')) { - dispatch(revealStatus(status.get('id'))); + dispatch(revealStatus(status.get('id'))) } else { - dispatch(hideStatus(status.get('id'))); + dispatch(hideStatus(status.get('id'))) } }, -}); +}) -export default connect(makeMapStateToProps, mapDispatchToProps)(Notification); +export default connect(makeMapStateToProps, mapDispatchToProps)(Notification) diff --git a/app/javascript/gabsocial/features/notifications/notifications.js b/app/javascript/gabsocial/features/notifications/notifications.js index f23cab36..e134728e 100644 --- a/app/javascript/gabsocial/features/notifications/notifications.js +++ b/app/javascript/gabsocial/features/notifications/notifications.js @@ -1,19 +1,20 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import { createSelector } from 'reselect'; -import { List as ImmutableList } from 'immutable'; -import { debounce } from 'lodash'; +import ImmutablePropTypes from 'react-immutable-proptypes' +import ImmutablePureComponent from 'react-immutable-pure-component' +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl' +import { createSelector } from 'reselect' +import { List as ImmutableList } from 'immutable' +import { debounce } from 'lodash' import { expandNotifications, scrollTopNotifications, dequeueNotifications, -} from '../../actions/notifications'; -import NotificationContainer from './containers/notification_container'; -// import ColumnSettingsContainer from './containers/column_settings_container'; -import ScrollableList from '../../components/scrollable_list'; -import LoadMore from '../../components/load_more'; -import TimelineQueueButtonHeader from '../../components/timeline_queue_button_header'; +} from '../../actions/notifications' +import NotificationContainer from './containers/notification_container' +// import ColumnSettingsContainer from './containers/column_settings_container' +import ScrollableList from '../../components/scrollable_list' +import LoadMore from '../../components/load_more' +import TimelineQueueButtonHeader from '../../components/timeline_queue_button_header' +import Block from '../../components/block' const getNotifications = createSelector([ state => state.getIn(['settings', 'notifications', 'quickFilter', 'show']), @@ -25,10 +26,10 @@ const getNotifications = createSelector([ // used if user changed the notification settings after loading the notifications from the server // otherwise a list of notifications will come pre-filtered from the backend // we need to turn it off for FilterBar in order not to block ourselves from seeing a specific category - return notifications.filterNot(item => item !== null && excludedTypes.includes(item.get('type'))); + return notifications.filterNot(item => item !== null && excludedTypes.includes(item.get('type'))) } - return notifications.filter(item => item !== null && allowedType === item.get('type')); -}); + return notifications.filter(item => item !== null && allowedType === item.get('type')) +}) const mapStateToProps = state => ({ showFilterBar: state.getIn(['settings', 'notifications', 'quickFilter', 'show']), @@ -37,7 +38,7 @@ const mapStateToProps = state => ({ isUnread: state.getIn(['notifications', 'unread']) > 0, hasMore: state.getIn(['notifications', 'hasMore']), totalQueuedNotificationsCount: state.getIn(['notifications', 'totalQueuedNotificationsCount'], 0), -}); +}) export default @connect(mapStateToProps) @@ -54,73 +55,81 @@ class Notifications extends ImmutablePureComponent { hasMore: PropTypes.bool, dequeueNotifications: PropTypes.func, totalQueuedNotificationsCount: PropTypes.number, - }; + } componentWillUnmount () { - this.handleLoadOlder.cancel(); - this.handleScrollToTop.cancel(); - this.handleScroll.cancel(); - this.props.dispatch(scrollTopNotifications(false)); + this.handleLoadOlder.cancel() + this.handleScrollToTop.cancel() + this.handleScroll.cancel() + this.props.dispatch(scrollTopNotifications(false)) } componentDidMount() { - this.handleDequeueNotifications(); - this.props.dispatch(scrollTopNotifications(true)); + this.handleDequeueNotifications() + this.props.dispatch(scrollTopNotifications(true)) } handleLoadGap = (maxId) => { - this.props.dispatch(expandNotifications({ maxId })); - }; + this.props.dispatch(expandNotifications({ maxId })) + } handleLoadOlder = debounce(() => { - const last = this.props.notifications.last(); - this.props.dispatch(expandNotifications({ maxId: last && last.get('id') })); - }, 300, { leading: true }); + const last = this.props.notifications.last() + this.props.dispatch(expandNotifications({ maxId: last && last.get('id') })) + }, 300, { leading: true }) handleScrollToTop = debounce(() => { - this.props.dispatch(scrollTopNotifications(true)); - }, 100); + this.props.dispatch(scrollTopNotifications(true)) + }, 100) handleScroll = debounce(() => { - this.props.dispatch(scrollTopNotifications(false)); - }, 100); + this.props.dispatch(scrollTopNotifications(false)) + }, 100) setColumnRef = c => { - this.column = c; + this.column = c } handleMoveUp = id => { - const elementIndex = this.props.notifications.findIndex(item => item !== null && item.get('id') === id) - 1; - this._selectChild(elementIndex, true); + const elementIndex = this.props.notifications.findIndex(item => item !== null && item.get('id') === id) - 1 + this._selectChild(elementIndex, true) } handleMoveDown = id => { - const elementIndex = this.props.notifications.findIndex(item => item !== null && item.get('id') === id) + 1; - this._selectChild(elementIndex, false); + const elementIndex = this.props.notifications.findIndex(item => item !== null && item.get('id') === id) + 1 + this._selectChild(elementIndex, false) } _selectChild (index, align_top) { - const container = this.column.node; - const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`); + const container = this.column.node + const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`) if (element) { if (align_top && container.scrollTop > element.offsetTop) { - element.scrollIntoView(true); + element.scrollIntoView(true) } else if (!align_top && container.scrollTop + container.clientHeight < element.offsetTop + element.offsetHeight) { - element.scrollIntoView(false); + element.scrollIntoView(false) } - element.focus(); + element.focus() } } handleDequeueNotifications = () => { - this.props.dispatch(dequeueNotifications()); - }; + this.props.dispatch(dequeueNotifications()) + } render () { - const { intl, notifications, isLoading, isUnread, hasMore, showFilterBar, totalQueuedNotificationsCount } = this.props; + const { + intl, + notifications, + isLoading, + isUnread, + hasMore, + showFilterBar, + totalQueuedNotificationsCount + } = this.props - let scrollableContent = null; + let scrollableContent = null // : todo : include follow requests @@ -157,7 +166,7 @@ class Notifications extends ImmutablePureComponent { console.log('filteredNotifications:', filteredNotifications) if (isLoading && this.scrollableContent) { - scrollableContent = this.scrollableContent; + scrollableContent = this.scrollableContent } else if (notifications.size > 0 || hasMore) { scrollableContent = notifications.map((item, index) => item === null ? ( ) : ( - )); + )) } else { - scrollableContent = null; + scrollableContent = null } - this.scrollableContent = scrollableContent; + this.scrollableContent = scrollableContent return (
@@ -191,18 +199,20 @@ class Notifications extends ImmutablePureComponent { itemType='notification' /> - } - onLoadMore={this.handleLoadOlder} - onScrollToTop={this.handleScrollToTop} - onScroll={this.handleScroll} - > - { scrollableContent } - + + } + onLoadMore={this.handleLoadOlder} + onScrollToTop={this.handleScrollToTop} + onScroll={this.handleScroll} + > + { scrollableContent } + +
) } diff --git a/app/javascript/gabsocial/features/standalone/compose/compose.js b/app/javascript/gabsocial/features/standalone/compose/compose.js deleted file mode 100644 index d9dbd40a..00000000 --- a/app/javascript/gabsocial/features/standalone/compose/compose.js +++ /dev/null @@ -1,19 +0,0 @@ -import ComposeFormContainer from '../../compose/containers/compose_form_container'; -import NotificationsContainer from '../../../containers/notifications_container'; -import LoadingBarContainer from '../../../containers/loading_bar_container'; -import ModalRoot from '../../../components/modal/modal_root' - -export default class Compose extends PureComponent { - - render() { - return ( -
- - - - -
- ); - } - -} diff --git a/app/javascript/gabsocial/features/standalone/compose/index.js b/app/javascript/gabsocial/features/standalone/compose/index.js deleted file mode 100644 index f5631b80..00000000 --- a/app/javascript/gabsocial/features/standalone/compose/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './compose' \ No newline at end of file diff --git a/app/javascript/gabsocial/features/standalone/hashtag_timeline/hashtag_timeline.js b/app/javascript/gabsocial/features/standalone/hashtag_timeline/hashtag_timeline.js deleted file mode 100644 index 22d3cd10..00000000 --- a/app/javascript/gabsocial/features/standalone/hashtag_timeline/hashtag_timeline.js +++ /dev/null @@ -1,83 +0,0 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import Masonry from 'react-masonry-infinite'; -import { List as ImmutableList } from 'immutable'; -import { debounce } from 'lodash'; -import { expandHashtagTimeline } from '../../../actions/timelines'; -import DetailedStatusContainer from '../../../features/status/containers/detailed_status_container'; -import ColumnIndicator from '../../../components/column_indicator'; - -const mapStateToProps = (state, { hashtag }) => ({ - statusIds: state.getIn(['timelines', `hashtag:${hashtag}`, 'items'], ImmutableList()), - isLoading: state.getIn(['timelines', `hashtag:${hashtag}`, 'isLoading'], false), - hasMore: state.getIn(['timelines', `hashtag:${hashtag}`, 'hasMore'], false), -}); - -export default -@connect(mapStateToProps) -class HashtagTimeline extends ImmutablePureComponent { - - static propTypes = { - dispatch: PropTypes.func.isRequired, - statusIds: ImmutablePropTypes.list.isRequired, - isLoading: PropTypes.bool.isRequired, - hasMore: PropTypes.bool.isRequired, - hashtag: PropTypes.string.isRequired, - }; - - componentDidMount () { - const { dispatch, hashtag } = this.props; - - dispatch(expandHashtagTimeline(hashtag)); - } - - handleLoadMore = () => { - const maxId = this.props.statusIds.last(); - - if (maxId) { - this.props.dispatch(expandHashtagTimeline(this.props.hashtag, { maxId })); - } - } - - setRef = c => { - this.masonry = c; - } - - handleHeightChange = debounce(() => { - if (!this.masonry) { - return; - } - - this.masonry.forcePack(); - }, 50) - - render () { - const { statusIds, hasMore, isLoading } = this.props; - - const sizes = [ - { columns: 1, gutter: 0 }, - { mq: '415px', columns: 1, gutter: 10 }, - { mq: '640px', columns: 2, gutter: 10 }, - { mq: '960px', columns: 3, gutter: 10 }, - { mq: '1255px', columns: 3, gutter: 10 }, - ]; - - const loader = (isLoading && statusIds.isEmpty()) ? : undefined; - - return ( - - {statusIds.map(statusId => ( -
- -
- )).toArray()} -
- ); - } - -} diff --git a/app/javascript/gabsocial/features/standalone/hashtag_timeline/index.js b/app/javascript/gabsocial/features/standalone/hashtag_timeline/index.js deleted file mode 100644 index 5d53e90d..00000000 --- a/app/javascript/gabsocial/features/standalone/hashtag_timeline/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './hashtag_timeline' \ No newline at end of file diff --git a/app/javascript/gabsocial/features/standalone/public_timeline/index.js b/app/javascript/gabsocial/features/standalone/public_timeline/index.js deleted file mode 100644 index c08f53fe..00000000 --- a/app/javascript/gabsocial/features/standalone/public_timeline/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './public_timeline' \ No newline at end of file diff --git a/app/javascript/gabsocial/features/standalone/public_timeline/public_timeline.js b/app/javascript/gabsocial/features/standalone/public_timeline/public_timeline.js deleted file mode 100644 index 335282c2..00000000 --- a/app/javascript/gabsocial/features/standalone/public_timeline/public_timeline.js +++ /dev/null @@ -1,98 +0,0 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import Masonry from 'react-masonry-infinite'; -import { List as ImmutableList, Map as ImmutableMap } from 'immutable'; -import { debounce } from 'lodash'; -import { expandPublicTimeline, expandCommunityTimeline } from '../../../actions/timelines'; -import DetailedStatusContainer from '../../../features/status/containers/detailed_status_container'; -import ColumnIndicator from '../../../components/column_indicator'; - -const mapStateToProps = (state, { local }) => { - const timeline = state.getIn(['timelines', local ? 'community' : 'public'], ImmutableMap()); - - return { - statusIds: timeline.get('items', ImmutableList()), - isLoading: timeline.get('isLoading', false), - hasMore: timeline.get('hasMore', false), - }; -}; - -export default -@connect(mapStateToProps) -class PublicTimeline extends ImmutablePureComponent { - - static propTypes = { - dispatch: PropTypes.func.isRequired, - statusIds: ImmutablePropTypes.list.isRequired, - isLoading: PropTypes.bool.isRequired, - hasMore: PropTypes.bool.isRequired, - local: PropTypes.bool, - }; - - componentDidMount () { - this._connect(); - } - - componentDidUpdate (prevProps) { - if (prevProps.local !== this.props.local) { - this._connect(); - } - } - - _connect () { - const { dispatch, local } = this.props; - - dispatch(local ? expandCommunityTimeline() : expandPublicTimeline()); - } - - handleLoadMore = () => { - const { dispatch, statusIds, local } = this.props; - const maxId = statusIds.last(); - - if (maxId) { - dispatch(local ? expandCommunityTimeline({ maxId }) : expandPublicTimeline({ maxId })); - } - } - - setRef = c => { - this.masonry = c; - } - - handleHeightChange = debounce(() => { - if (!this.masonry) { - return; - } - - this.masonry.forcePack(); - }, 50) - - render () { - const { statusIds, hasMore, isLoading } = this.props; - - const sizes = [ - { columns: 1, gutter: 0 }, - { mq: '415px', columns: 1, gutter: 10 }, - { mq: '640px', columns: 2, gutter: 10 }, - { mq: '960px', columns: 3, gutter: 10 }, - { mq: '1255px', columns: 3, gutter: 10 }, - ]; - - const loader = (isLoading && statusIds.isEmpty()) ? : undefined; - - return ( - - {statusIds.map(statusId => ( -
- -
- )).toArray()} -
- ); - } - -} diff --git a/app/javascript/gabsocial/features/status/components/card/card.js b/app/javascript/gabsocial/features/status/components/card/card.js index bb32db2d..0d13916a 100644 --- a/app/javascript/gabsocial/features/status/components/card/card.js +++ b/app/javascript/gabsocial/features/status/components/card/card.js @@ -124,7 +124,7 @@ export default class Card extends ImmutablePureComponent { return (
) diff --git a/app/javascript/gabsocial/features/status/components/detailed_status/detailed_status.js b/app/javascript/gabsocial/features/status/components/detailed_status/detailed_status.js deleted file mode 100644 index 77a320b4..00000000 --- a/app/javascript/gabsocial/features/status/components/detailed_status/detailed_status.js +++ /dev/null @@ -1,218 +0,0 @@ -import { Link, NavLink } from 'react-router-dom'; -import { FormattedDate, FormattedNumber } from 'react-intl'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import classNames from 'classnames'; -import scheduleIdleTask from '../../../../utils/schedule_idle_task'; -import StatusQuote from '../../../../components/status_quote'; -import Avatar from '../../../../components/avatar'; -import DisplayName from '../../../../components/display_name'; -import StatusContent from '../../../../components/status_content'; -import MediaGallery from '../../../../components/media_gallery'; -import Icon from '../../../../components/icon'; -import Poll from '../../../../components/poll'; -import Card from '../card'; -import Video from '../../../video'; - -export default class DetailedStatus extends ImmutablePureComponent { - - static contextTypes = { - router: PropTypes.object, - }; - - static propTypes = { - status: ImmutablePropTypes.map, - onOpenMedia: PropTypes.func.isRequired, - onOpenVideo: PropTypes.func.isRequired, - onToggleHidden: PropTypes.func.isRequired, - measureHeight: PropTypes.bool, - onHeightChange: PropTypes.func, - domain: PropTypes.string.isRequired, - compact: PropTypes.bool, - showMedia: PropTypes.bool, - onToggleMediaVisibility: PropTypes.func, - onShowRevisions: PropTypes.func, - }; - - state = { - height: null, - }; - - handleShowRevisions = () => { - this.props.onShowRevisions(this.props.status); - } - - handleOpenVideo = (media, startTime) => { - this.props.onOpenVideo(media, startTime); - } - - handleExpandedToggle = () => { - this.props.onToggleHidden(this.props.status); - } - - _measureHeight (heightJustChanged) { - if (this.props.measureHeight && this.node) { - scheduleIdleTask(() => this.node && this.setState({ height: Math.ceil(this.node.scrollHeight) + 1 })); - - if (this.props.onHeightChange && heightJustChanged) { - this.props.onHeightChange(); - } - } - } - - setRef = c => { - this.node = c; - this._measureHeight(); - } - - componentDidUpdate (prevProps, prevState) { - this._measureHeight(prevState.height !== this.state.height); - } - - handleModalLink = e => { - e.preventDefault(); - - let href; - - if (e.target.nodeName !== 'A') { - href = e.target.parentNode.href; - } else { - href = e.target.href; - } - - window.open(href, 'gabsocial-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes'); - } - - render () { - const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status; - const outerStyle = { boxSizing: 'border-box' }; - const { compact } = this.props; - - if (!status) { - return null; - } - - let media = ''; - let applicationLink = ''; - let reblogLink = ''; - let reblogIcon = 'retweet'; - let favouriteLink = ''; - - if (this.props.measureHeight) { - outerStyle.height = `${this.state.height}px`; - } - - if (status.get('poll')) { - media = ; - } else if (status.get('media_attachments').size > 0) { - if (status.getIn(['media_attachments', 0, 'type']) === 'video') { - const video = status.getIn(['media_attachments', 0]); - - media = ( -