This commit is contained in:
mgabdev 2020-04-11 18:29:19 -04:00
parent 7249143d9f
commit 595208780e
160 changed files with 1678 additions and 2103 deletions

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true
class Api::V1::Accounts::IdentityProofsController < Api::BaseController
before_action :require_user!
before_action :set_account
respond_to :json

View File

@ -102,7 +102,7 @@ export function fetchAccount(id) {
return (dispatch, getState) => {
dispatch(fetchRelationships([id]));
if (getState().getIn(['accounts', id], null) !== null) {
if (id === -1 || getState().getIn(['accounts', id], null) !== null) {
return;
}

View File

@ -165,9 +165,12 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
// filter verified and following here too
const params = {
max_id: maxId,
only_verified: onlyVerified,
only_following: onlyFollowing,
exclude_types: activeFilter === 'all' ? [] : excludeTypesFromFilter(activeFilter),
// only_verified: onlyVerified,
// only_following: onlyFollowing,
exclude_types: activeFilter === 'all' ? null : excludeTypesFromFilter(activeFilter),
// exclude_types: activeFilter === 'all'
// ? excludeTypesFromSettings(getState())
// : excludeTypesFromFilter(activeFilter),
};
if (!maxId && notifications.get('items').size > 0) {
@ -176,6 +179,8 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
dispatch(expandNotificationsRequest(isLoadingMore));
console.log("params:", params)
api(getState).get('/api/v1/notifications', { params }).then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');

View File

@ -1,15 +1,17 @@
import api from '../api';
import { importFetchedAccounts } from './importer';
import { me } from '../initial_state';
import api from '../api'
import { importFetchedAccounts } from './importer'
import { me } from '../initial_state'
export const SUGGESTIONS_FETCH_REQUEST = 'SUGGESTIONS_FETCH_REQUEST';
export const SUGGESTIONS_FETCH_SUCCESS = 'SUGGESTIONS_FETCH_SUCCESS';
export const SUGGESTIONS_FETCH_FAIL = 'SUGGESTIONS_FETCH_FAIL';
export const SUGGESTIONS_FETCH_REQUEST = 'SUGGESTIONS_FETCH_REQUEST'
export const SUGGESTIONS_FETCH_SUCCESS = 'SUGGESTIONS_FETCH_SUCCESS'
export const SUGGESTIONS_FETCH_FAIL = 'SUGGESTIONS_FETCH_FAIL'
export const SUGGESTIONS_DISMISS = 'SUGGESTIONS_DISMISS';
export function fetchSuggestions() {
return (dispatch, getState) => {
if (!me) return false
dispatch(fetchSuggestionsRequest());
api(getState).get('/api/v1/suggestions').then(response => {

View File

@ -4,6 +4,18 @@ import ImmutablePropTypes from 'react-immutable-proptypes'
import { defineMessages, injectIntl } from 'react-intl'
import ImmutablePureComponent from 'react-immutable-pure-component'
import { me } from '../initial_state'
import {
followAccount,
unfollowAccount,
blockAccount,
unblockAccount,
muteAccount,
unmuteAccount,
} from '../actions/accounts'
import { openModal } from '../actions/modal'
import { initMuteModal } from '../actions/mutes'
import { unfollowModal } from '../initial_state'
import { makeGetAccount } from '../selectors'
import Avatar from './avatar'
import DisplayName from './display_name'
import Button from './button'
@ -17,10 +29,60 @@ const messages = defineMessages({
unmute: { id: 'unmute', defaultMessage: 'Unmute' },
mute_notifications: { id: 'account.mute_notifications', defaultMessage: 'Mute notifications from @{name}' },
unmute_notifications: { id: 'account.unmute_notifications', defaultMessage: 'Unmute notifications from @{name}' },
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
})
const makeMapStateToProps = () => {
const getAccount = makeGetAccount()
const mapStateToProps = (state, props) => ({
account: getAccount(state, props.id),
})
return mapStateToProps
}
const mapDispatchToProps = (dispatch, { intl }) => ({
onFollow (account) {
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
if (unfollowModal) {
dispatch(openModal('UNFOLLOW', {
accountId: account.get('id'),
}))
} else {
dispatch(unfollowAccount(account.get('id')))
}
} else {
dispatch(followAccount(account.get('id')))
}
},
onBlock (account) {
if (account.getIn(['relationship', 'blocking'])) {
dispatch(unblockAccount(account.get('id')))
} else {
dispatch(blockAccount(account.get('id')))
}
},
onMute (account) {
if (account.getIn(['relationship', 'muting'])) {
dispatch(unmuteAccount(account.get('id')))
} else {
dispatch(initMuteModal(account))
}
},
onMuteNotifications (account, notifications) {
dispatch(muteAccount(account.get('id'), notifications))
},
})
export default
@injectIntl
@connect(makeMapStateToProps, mapDispatchToProps)
class Account extends ImmutablePureComponent {
static propTypes = {

View File

@ -1,4 +1,4 @@
import classNames from 'classnames/bind'
wimport classNames from 'classnames/bind'
const cx = classNames.bind(_s)

View File

@ -1,8 +1,8 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { makeGetAccount } from '../../selectors';
import Avatar from '../avatar';
import DisplayName from '../display_name';
import { makeGetAccount } from '../selectors';
import Avatar from './avatar';
import DisplayName from './display_name';
const makeMapStateToProps = () => {
const getAccount = makeGetAccount();
@ -20,7 +20,7 @@ class AutosuggestAccount extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map.isRequired,
};
}
render () {
const { account } = this.props;

View File

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

View File

@ -1,7 +1,36 @@
import unicodeMapping from '../emoji/emoji_unicode_mapping_light'
import unicodeMapping from './emoji/emoji_unicode_mapping_light'
const assetHost = process.env.CDN_HOST || ''
// .autosuggest-emoji {
// display: flex;
// justify-items: center;
// align-content: flex-start;
// flex-direction: row;
// @include text-sizing(14px, 400, 18px);
// img {
// display: block;
// margin-right: 8px;
// @include size(16px);
// }
// }
// .emojione {
// font-size: inherit;
// vertical-align: middle;
// object-fit: contain;
// margin: -.2ex .15em .2ex;
// @include size(16px);
// img {
// width: auto;
// }
// }
export default class AutosuggestEmoji extends PureComponent {
static propTypes = {

View File

@ -1,28 +0,0 @@
.autosuggest-emoji {
display: flex;
justify-items: center;
align-content: flex-start;
flex-direction: row;
@include text-sizing(14px, 400, 18px);
img {
display: block;
margin-right: 8px;
@include size(16px);
}
}
.emojione {
font-size: inherit;
vertical-align: middle;
object-fit: contain;
margin: -.2ex .15em .2ex;
@include size(16px);
img {
width: auto;
}
}

View File

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

View File

@ -2,12 +2,12 @@ import { Fragment } from 'react'
import ImmutablePropTypes from 'react-immutable-proptypes'
import classNames from 'classnames/bind'
import ImmutablePureComponent from 'react-immutable-pure-component'
import { isRtl } from '../../utils/rtl'
import { textAtCursorMatchesToken } from '../../utils/cursor_token_match'
import AutosuggestAccount from '../autosuggest_account'
import AutosuggestEmoji from '../autosuggest_emoji'
import Input from '../input'
import Composer from '../composer'
import { isRtl } from '../utils/rtl'
import { textAtCursorMatchesToken } from '../utils/cursor_token_match'
import AutosuggestAccount from './autosuggest_account'
import AutosuggestEmoji from './autosuggest_emoji'
import Input from './input'
import Composer from './composer'
const cx = classNames.bind(_s)

View File

@ -1,83 +0,0 @@
.autosuggest-input {
position: relative;
}
.autosuggest-textarea {
&__suggestions-wrapper {
position: relative;
height: 0;
}
&__wrapper {
position: relative;
}
&__textarea {
display: block;
box-sizing: border-box;
min-height: 100px;
border-radius: 5px 5px 0 0;
resize: none;
scrollbar-color: initial;
padding: 14px 32px 13px 10px !important;
width: 100%;
margin: 0;
color: $inverted-text-color;
background: $simple-background-color;
font-family: inherit;
font-size: 14px;
resize: vertical;
border: 0;
outline: 0;
body.theme-gabsocial-light & {
background: $gab-background-base-light;
}
&:focus {
outline: 0;
}
&::-webkit-scrollbar {
all: unset;
}
@include breakpoint(sm) {
max-height: 100px !important; // prevent auto-resize textarea
resize: vertical;
font-size: 16px;
}
}
&__suggestions {
display: none;
box-sizing: border-box;
position: absolute;
top: 100%;
width: 100%;
z-index: 9999;
box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);
background: $ui-secondary-color;
color: $inverted-text-color;
border-radius: 0 0 4px 4px;
font-size: 14px;
padding: 6px;
&--visible {
display: block;
}
&__item {
padding: 10px;
cursor: pointer;
border-radius: 4px;
&:hover,
&:focus,
&:active,
&.selected {
background: darken($ui-secondary-color, 10%);
}
}
}
}

View File

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

View File

@ -137,7 +137,7 @@ const compositeDecorator = new CompositeDecorator([
const HANDLE_REGEX = /\@[\w]+/g;
const HASHTAG_REGEX = /\#[\w\u0590-\u05ff]+/g;
const mapStateToProps = state => {
const mapStateToProps = (state) => {
const getAccount = makeGetAccount()
const account = getAccount(state, me)
const isPro = account.get('is_pro')
@ -148,11 +148,9 @@ const mapStateToProps = state => {
}
}
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
}
}
})
export default
@connect(mapStateToProps, mapDispatchToProps)

View File

@ -7,7 +7,7 @@ import Icon from './icon'
const cx = classNames.bind(_s)
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
openUserInfoPopover(props) {
dispatch(openPopover('USER_INFO', props))
},

View File

@ -38,6 +38,16 @@ export default class ExtendedVideoPlayer extends PureComponent {
render () {
const { src, muted, controls, alt } = this.props;
// .extended-video-player {
// @include size(100%);
// @include flex(center, center);
// video {
// @include max-size($media-modal-media-max-width, $media-modal-media-max-height);
// }
// }
return (
<div className='extended-video-player'>
<video

View File

@ -1,8 +0,0 @@
.extended-video-player {
@include size(100%);
@include flex(center, center);
video {
@include max-size($media-modal-media-max-width, $media-modal-media-max-height);
}
}

View File

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

View File

@ -4,17 +4,14 @@ export default class FloatingActionButton extends PureComponent {
static propTypes = {
onClick: PropTypes.func.isRequired,
message: PropTypes.string.isRequired,
};
}
shouldComponentUpdate(nextProps) {
return nextProps.message !== this.props.message;
return nextProps.message !== this.props.message
}
render() {
const { onClick, message } = this.props;
// const shouldHideFAB = path => path.match(/^\/posts\/|^\/search|^\/getting-started/);
// const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : <button key='floating-action-button' onClick={this.handleOpenComposeModal} className='floating-action-button' aria-label={intl.formatMessage(messages.publish)}></button>;
const { onClick, message } = this.props
return (
<Button

View File

@ -0,0 +1,121 @@
import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
import classNames from 'classnames/bind'
import { openPopover, closePopover } from '../actions/popover'
import { initReport } from '../actions/reports'
import { openModal } from '../actions/modal'
import { unfollowModal, me } from '../initial_state'
import Avatar from './avatar'
import Button from './button'
import Block from './block'
import Icon from './icon'
import Image from './image'
import TabBar from './tab_bar'
import Text from './text'
const cx = classNames.bind(_s)
const messages = defineMessages({
follow: { id: 'follow', defaultMessage: 'Follow' },
unfollow: { id: 'unfollow', defaultMessage: 'Unfollow' },
requested: { id: 'requested', defaultMessage: 'Requested' },
unblock: { id: 'unblock', defaultMessage: 'Unblock' },
followers: { id: 'account.followers', defaultMessage: 'Followers' },
follows: { id: 'account.follows', defaultMessage: 'Follows' },
profile: { id: 'account.profile', defaultMessage: 'Profile' },
})
const mapDispatchToProps = (dispatch, { intl }) => ({
openProfileOptionsPopover(props) {
console.log('props:', props)
dispatch(openPopover('PROFILE_OPTIONS', props))
},
});
export default
@connect(null, mapDispatchToProps)
@injectIntl
class GroupHeader extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
group: ImmutablePropTypes.map,
relationships: ImmutablePropTypes.map,
}
render() {
const { intl, relationships, group } = this.props
const tabs = !group ? null : [
{
to: `/groups/${group.get('id')}`,
title: 'Latest',
},
{
to: `/groups/${group.get('id')}/pinned`,
title: 'Pinned',
},
{
to: `/groups/${group.get('id')}/popular`,
title: 'Popular',
},
]
const coverSrc = !!group ? group.get('cover') : undefined
const title = !!group ? group.get('title') : undefined
return (
<div className={[_s.default, _s.z1, _s.width100PC, _s.mb15].join(' ')}>
<Block>
<div className={[_s.default, _s.width100PC].join(' ')}>
{
!!coverSrc &&
<Image className={_s.height350PX} src={coverSrc} alt={title} />
}
<div className={[_s.default, _s.height53PX, _s.width100PC].join(' ')}>
<div className={[_s.default, _s.flexRow, _s.height100PC, _s.px10].join(' ')}>
<TabBar tabs={tabs} />
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.height100PC, _s.marginLeftAuto].join(' ')}>
<Button
color='primary'
backgroundColor='tertiary'
radiusSmall
className={_s.mr5}
>
<Text color='inherit' size='small'>
Leave/Join
</Text>
</Button>
<Button
color='primary'
backgroundColor='tertiary'
radiusSmall
className={_s.mr5}
>
<Text color='inherit' size='small'>
Share
</Text>
</Button>
<Button
radiusSmall
color='primary'
backgroundColor='tertiary'
className={_s.mr5}
icon='ellipsis'
/>
</div>
</div>
</div>
</div>
</Block>
</div>
)
}
}

View File

@ -1,6 +1,30 @@
import classNames from 'classnames';
import { LoadingBar } from 'react-redux-loading-bar';
import ZoomableImage from '../zoomable_image';
import ZoomableImage from './zoomable_image';
// .image-loader {
// position: relative;
// @include flex(center, center, column);
// @include size(100%);
// &__preview-canvas {
// object-fit: contain;
// @include max-size($media-modal-media-max-width, $media-modal-media-max-height);
// @include background-image("", contain, center, repeat);
// }
// &--amorphous & {
// &__preview-canvas {
// display: none;
// }
// }
// .loading-bar {
// position: relative;
// }
// }
export default class ImageLoader extends PureComponent {

View File

@ -1,23 +0,0 @@
.image-loader {
position: relative;
@include flex(center, center, column);
@include size(100%);
&__preview-canvas {
object-fit: contain;
@include max-size($media-modal-media-max-width, $media-modal-media-max-height);
@include background-image("", contain, center, repeat);
}
&--amorphous & {
&__preview-canvas {
display: none;
}
}
.loading-bar {
position: relative;
}
}

View File

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

View File

@ -2,6 +2,6 @@ import LoadingBar from 'react-redux-loading-bar'
const mapStateToProps = (state, ownProps) => ({
loading: state.get('loadingBar')[ownProps.scope || 'default'],
});
})
export default connect(mapStateToProps)(LoadingBar.WrappedComponent)

View File

@ -4,12 +4,12 @@ import { is } from 'immutable';
import { defineMessages, injectIntl } from 'react-intl';
import classNames from 'classnames/bind'
import { decode } from 'blurhash';
import { autoPlayGif, displayMedia } from '../../initial_state';
import { isIOS } from '../../utils/is_mobile';
import { isPanoramic, isPortrait, isNonConformingRatio, minimumAspectRatio, maximumAspectRatio } from '../../utils/media_aspect_ratio';
import Button from '../button'
import SensitiveMediaItem from '../../components/sensitive_media_item'
import Text from '../text'
import { autoPlayGif, displayMedia } from '../initial_state';
import { isIOS } from '../utils/is_mobile';
import { isPanoramic, isPortrait, isNonConformingRatio, minimumAspectRatio, maximumAspectRatio } from '../utils/media_aspect_ratio';
import Button from './button'
import SensitiveMediaItem from './sensitive_media_item'
import Text from './text'
const messages = defineMessages({
toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' },

View File

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

View File

@ -1,144 +0,0 @@
.media-item {
display: block;
float: left;
border: none;
box-sizing: border-box;
position: relative;
overflow: hidden;
&.standalone {
media-item-gifv-thumbnail {
transform: none;
top: 0;
}
}
&__thumbnail {
display: block;
cursor: zoom-in;
text-decoration: none;
color: $secondary-text-color;
line-height: 0;
position: relative;
z-index: 1;
&,
img {
@include size(100%);
}
img {
object-fit: cover;
}
}
&__gifv {
cursor: zoom-in;
object-fit: cover;
position: relative;
top: 50%;
transform: translateY(-50%);
z-index: 1;
@include size(100%);
}
}
.media-gallery {
box-sizing: border-box;
margin-top: 8px;
overflow: hidden;
position: relative;
width: 100%;
&__preview {
object-fit: cover;
z-index: 0;
background: $base-overlay-background;
@include size(100%);
@include abs-position(0, auto, auto, 0);
&--hidden {
display: none;
}
}
&__gifv {
overflow: hidden;
position: relative;
@include size(100%);
&.autoplay {
.media-gallery__gifv__label {
display: none;
}
}
&:hover {
.media-gallery__gifv__label {
opacity: 1;
}
}
&__label {
display: block;
color: $primary-text-color;
background: rgba($base-overlay-background, 0.5);
padding: 2px 6px;
border-radius: 2px;
z-index: 1;
pointer-events: none;
opacity: 0.9;
transition: opacity 0.1s ease;
@include text-sizing(11px, 600, 18px);
@include abs-position(auto, auto, 6px, 6px);
}
}
}
.spoiler-button {
z-index: 100;
@include size(100%);
@include abs-position(0, auto, auto, 0);
&--minified {
display: block;
@include size(auto);
@include abs-position(4px, auto, auto, 4px, false);
}
&--hidden {
display: none;
}
&__overlay {
display: block;
background: transparent;
border: 0;
@include size(100%);
&__label {
display: inline-block;
background: rgba($base-overlay-background, 0.5);
border-radius: 8px;
padding: 8px 12px;
color: $primary-text-color;
@include text-sizing(14px, 500);
}
&:hover,
&:focus,
&:active {
.spoiler-button__overlay__label {
background: rgba($base-overlay-background, 0.8);
}
}
}
}

View File

@ -17,13 +17,11 @@ const mapStateToProps = (state, { accountId }) => {
}
}
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
onConfirm(account) {
dispatch(blockAccount(account.get('id')))
},
}
}
})
export default
@connect(mapStateToProps, mapDispatchToProps)

View File

@ -9,13 +9,11 @@ const messages = defineMessages({
cancel: { id: 'confirmation_modal.cancel', defaultMessage: 'Cancel' },
})
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
onConfirm(domain) {
dispatch(blockDomain(domain))
},
}
}
})
export default
@connect(null, mapDispatchToProps)

View File

@ -14,7 +14,7 @@ const messages = defineMessages({
showInSidebar: { id: 'show_in_sidebar', defaultMessage: 'Show in Sidebar' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
settings: state.getIn(['settings', 'community']),
})

View File

@ -10,11 +10,9 @@ const messages = defineMessages({
title: { id: 'navigation_bar.compose', defaultMessage: 'Compose new gab' },
})
const mapStateToProps = state => {
return {
const mapStateToProps = (state) => ({
composeText: state.getIn(['compose', 'text']),
};
}
})
export default
@connect(mapStateToProps)

View File

@ -9,13 +9,11 @@ const messages = defineMessages({
delete: { id: 'delete', defaultMessage: 'Delete' },
})
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
onConfirm(account) {
// dispatch(blockAccount(account.get('id')))
},
}
}
})
export default
@connect(null, mapDispatchToProps)

View File

@ -7,20 +7,16 @@ const messages = defineMessages({
confirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' },
})
const mapStateToProps = state => {
return {
const mapStateToProps = (state) => ({
isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),
account: state.getIn(['mutes', 'new', 'account']),
}
}
})
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
onConfirm(account, notifications) {
dispatch(muteAccount(account.get('id'), notifications))
},
}
}
})
export default
@connect(mapStateToProps, mapDispatchToProps)

View File

@ -14,7 +14,7 @@ const messages = defineMessages({
showInSidebar: { id: 'show_in_sidebar', defaultMessage: 'Show in Sidebar' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
settings: state.getIn(['settings', 'community']),
})

View File

@ -17,7 +17,7 @@ const messages = defineMessages({
showReplies: { id: 'home.column_settings.show_replies', defaultMessage: 'Show replies' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
settings: state.getIn(['settings', 'home']),
})

View File

@ -9,13 +9,11 @@ const messages = defineMessages({
delete: { id: 'delete', defaultMessage: 'Delete' },
})
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
onConfirm(account) {
// dispatch(blockAccount(account.get('id')))
},
}
}
})
export default
@connect(null, mapDispatchToProps)

View File

@ -7,20 +7,16 @@ const messages = defineMessages({
confirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' },
})
const mapStateToProps = state => {
return {
const mapStateToProps = (state) => ({
isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),
account: state.getIn(['mutes', 'new', 'account']),
}
}
})
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
onConfirm(account, notifications) {
dispatch(muteAccount(account.get('id'), notifications))
},
}
}
})
export default
@connect(mapStateToProps, mapDispatchToProps)

View File

@ -17,7 +17,7 @@ const messages = defineMessages({
showReplies: { id: 'home.column_settings.show_replies', defaultMessage: 'Show replies' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
settings: state.getIn(['settings', 'list']),
})

View File

@ -9,7 +9,7 @@ const messages = defineMessages({
delete: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
composeId: state.getIn(['compose', 'id']),
composeText: state.getIn(['compose', 'text']),
})

View File

@ -68,7 +68,7 @@ const MODAL_COMPONENTS = {
VIDEO: () => Promise.resolve({ default: VideoModal }),
}
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
type: state.getIn(['modal', 'modalType']),
props: state.getIn(['modal', 'modalProps'], {}),
})

View File

@ -17,13 +17,11 @@ const mapStateToProps = (state, { accountId }) => {
}
}
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
onConfirm(account, notifications) {
dispatch(muteAccount(account.get('id'), notifications))
},
}
}
})
export default
@connect(mapStateToProps, mapDispatchToProps)

View File

@ -25,7 +25,7 @@ const messages = defineMessages({
const makeMapStateToProps = () => {
const getAccount = makeGetAccount()
const mapStateToProps = state => {
const mapStateToProps = (state) => {
const accountId = state.getIn(['reports', 'new', 'account_id'])
return {
@ -125,14 +125,14 @@ class ReportModal extends ImmutablePureComponent {
/>
</div>
{
{ /** : todo : */
domain &&
<div>
<Text color='secondary' size='small'>
{intl.formatMessage(messages.forwardHint)}
</Text>
<div className='setting-toggle'>
<div>
<Switch
id='report-forward'
checked={forward}

View File

@ -2,7 +2,6 @@ import { defineMessages, injectIntl } from 'react-intl'
import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
import classNames from 'classnames/bind'
// import StatusRevisionListContainer from '../../containers/status_revisions_list_container'
import { loadStatusRevisions } from '../../actions/status_revisions'
import ModalLayout from './modal_layout'
import RelativeTimestamp from '../relative_timestamp'
@ -15,13 +14,13 @@ const messages = defineMessages({
title: { id: 'status_revisions.heading', defaultMessage: 'Revision History' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
loading: state.getIn(['status_revisions', 'loading']),
error: state.getIn(['status_revisions', 'error']),
revisions: state.getIn(['status_revisions', 'revisions']),
})
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
onLoadStatusRevisions(statusId) {
dispatch(loadStatusRevisions(statusId))
},

View File

@ -7,20 +7,16 @@ const messages = defineMessages({
confirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' },
})
const mapStateToProps = state => {
return {
const mapStateToProps = (state) => ({
isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),
account: state.getIn(['mutes', 'new', 'account']),
}
}
})
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
onConfirm(account, notifications) {
dispatch(muteAccount(account.get('id'), notifications))
},
}
}
})
export default
@connect(mapStateToProps, mapDispatchToProps)

View File

@ -12,12 +12,13 @@ export default class MovedNote extends ImmutablePureComponent {
}
static propTypes = {
fromAcct: ImmutablePropTypes.map.isRequired,
to: ImmutablePropTypes.map.isRequired,
}
render () {
const { to } = this.props;
const displayNameHtml = { __html: from.get('display_name_html') }
const { fromAcct, toAcct } = this.props;
const displayNameHtml = { __html: fromAcct.get('display_name_html') }
return (
<div className='moved-note'>
@ -34,11 +35,11 @@ export default class MovedNote extends ImmutablePureComponent {
/>
</div>
<NavLink to={`/${this.props.to.get('acct')}`} className='moved-note__display-name'>
<NavLink to={`/${toAcct.get('acct')}`} className='moved-note__display-name'>
<div className='moved-note__display-avatar'>
<Avatar account={to} />
<Avatar account={toAcct} />
</div>
<DisplayName account={to} />
<DisplayName account={toAcct} />
</NavLink>
</div>
);

View File

@ -11,15 +11,13 @@ const messages = defineMessages({
show_all: { id: 'groups.sidebar-panel.show_all', defaultMessage: 'Show all' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
hashtags: state.getIn(['hashtags', 'items']),
})
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
fetchHashtags: () => dispatch(fetchHashtags()),
}
}
})
export default
@connect(mapStateToProps, mapDispatchToProps)

View File

@ -17,15 +17,13 @@ const messages = defineMessages({
edit: { id: 'edit', defaultMessage: 'Edit' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
// accountIds: state.getIn(['listEditor', 'accounts', 'items']),
})
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
}
}
})
export default
@connect(mapStateToProps, mapDispatchToProps)
@ -96,7 +94,7 @@ class ListDetailsPanel extends ImmutablePureComponent {
{
[1, 2, 3, 4, 5, 6, 7, 8, 9].map(item => (
<div className={[_s.default, _s.mr5].join(' ')}>
<Avatar size='26' />
<Avatar size={26} />
</div>
))
}

View File

@ -36,7 +36,7 @@ class MediaGalleryPanel extends ImmutablePureComponent {
componentDidMount() {
const { accountId } = this.props
if (accountId) {
if (accountId && accountId !== -1) {
this.props.dispatch(expandAccountMediaTimeline(accountId, { limit: 8 }))
}
}

View File

@ -1,6 +1,7 @@
import { defineMessages, injectIntl } from 'react-intl'
import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes'
import { me } from '../../initial_state'
import { setFilter } from '../../actions/notifications'
import PanelLayout from './panel_layout'
import SettingSwitch from '../setting_switch'
@ -11,17 +12,16 @@ const messages = defineMessages({
onlyFollowing: { id: 'notification_only_following', defaultMessage: 'Only People I Follow' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
settings: state.getIn(['notifications', 'filter']),
isPro: state.getIn(['accounts', me, 'is_pro']),
})
const mapDispatchToProps = (dispatch) => {
return {
const mapDispatchToProps = (dispatch) => ({
onChange(path, value) {
dispatch(setFilter(path, value))
},
}
}
})
export default
@injectIntl
@ -32,10 +32,18 @@ class NotificationFilterPanel extends ImmutablePureComponent {
intl: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
settings: ImmutablePropTypes.map.isRequired,
isPro: PropTypes.bool.isRequired,
}
render() {
const { intl, onChange, settings } = this.props
const {
intl,
onChange,
settings,
isPro
} = this.props
if (!isPro) return null
return (
<PanelLayout title={intl.formatMessage(messages.title)}>

View File

@ -25,12 +25,10 @@ const mapStateToProps = (state, { account }) => {
}
}
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
fetchSuggestions: () => dispatch(fetchSuggestions()),
dismissSuggestion: account => dispatch(dismissSuggestion(account.get('id'))),
}
}
})
export default
@connect(mapStateToProps, mapDispatchToProps)

View File

@ -10,15 +10,13 @@ const messages = defineMessages({
title: { id: 'trends.title', defaultMessage: 'Trending right now' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
gabtrends: state.getIn(['gab_trends', 'items']),
})
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
onFetchGabTrends: () => dispatch(fetchGabTrends()),
}
}
})
export default
@connect(mapStateToProps, mapDispatchToProps)

View File

@ -22,11 +22,9 @@ const messages = defineMessages({
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
})
const mapStateToProps = state => {
return {
const mapStateToProps = (state) => ({
account: makeGetAccount()(state, me),
}
}
})
export default
@connect(mapStateToProps)

View File

@ -2,7 +2,7 @@ import { defineMessages, injectIntl } from 'react-intl';
import { fetchSuggestions, dismissSuggestion } from '../../actions/suggestions';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import AccountContainer from '../../containers/account_container';
import Account from '../../components/account';
import PanelLayout from './panel_layout';
const messages = defineMessages({
@ -11,16 +11,14 @@ const messages = defineMessages({
show_more: { id: 'who_to_follow.more', defaultMessage: 'Show more' },
});
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
suggestions: state.getIn(['suggestions', 'items']),
});
const mapDispatchToProps = dispatch => {
return {
const mapDispatchToProps = (dispatch) => ({
fetchSuggestions: () => dispatch(fetchSuggestions()),
dismissSuggestion: account => dispatch(dismissSuggestion(account.get('id'))),
}
};
dismissSuggestion: (account) => dispatch(dismissSuggestion(account.get('id'))),
})
export default
@connect(mapStateToProps, mapDispatchToProps)
@ -56,7 +54,7 @@ class WhoToFollowPanel extends ImmutablePureComponent {
>
<div className={_s.default}>
{suggestions && suggestions.map(accountId => (
<AccountContainer
<Account
showDismiss
key={accountId}
id={accountId}

View File

@ -6,12 +6,12 @@ import PopoverLayout from './popover_layout'
// import 'react-datepicker/dist/react-datepicker.css'
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
date: state.getIn(['compose', 'scheduled_at']),
isPro: state.getIn(['accounts', me, 'is_pro']),
})
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
setScheduledAt (date) {
dispatch(changeScheduledAt(date))
},

View File

@ -346,7 +346,7 @@ const getCustomEmojis = createSelector([
return 0;
}));
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
custom_emojis: getCustomEmojis(state),
skinTone: state.getIn(['settings', 'skinTone']),
frequentlyUsedEmojis: getFrequentlyUsedEmojis(state),

View File

@ -12,7 +12,7 @@ const cx = classnames.bind(_s)
let id = 0
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
isModalOpen: state.getIn(['modal', 'modalType']) === 'ACTIONS',
popoverPlacement: state.getIn(['popover', 'placement']),
openPopoverType: state.getIn(['popover', 'popoverType']),

View File

@ -31,7 +31,7 @@ const POPOVER_COMPONENTS = {
USER_INFO: () => Promise.resolve({ default: UserInfoPopover }),
}
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
type: state.getIn(['popover', 'popoverType']),
props: state.getIn(['popover', 'popoverProps'], {}),
})

View File

@ -19,11 +19,11 @@ const messages = defineMessages({
visibility: { id: 'privacy.visibility', defaultMessage: 'Visibility' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
value: state.getIn(['compose', 'privacy']),
})
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
onChange (value) {
dispatch(changeComposeVisibility(value))

View File

@ -18,6 +18,7 @@ import Button from './button'
import DisplayName from './display_name'
import Icon from './icon'
import Image from './image'
import MovedNote from './moved_note'
import TabBar from './tab_bar'
import Text from './text'
@ -33,11 +34,9 @@ const messages = defineMessages({
profile: { id: 'account.profile', defaultMessage: 'Profile' },
})
const mapStateToProps = state => {
return {
const mapStateToProps = (state) => ({
}
}
})
const mapDispatchToProps = (dispatch, { intl }) => ({

View File

@ -6,29 +6,16 @@ import {
} from '../actions/search'
import Input from './input'
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
value: state.getIn(['search', 'value']),
submitted: state.getIn(['search', 'submitted']),
})
const mapDispatchToProps = dispatch => ({
onChange (value) {
dispatch(changeSearch(value))
},
onClear () {
dispatch(clearSearch())
},
onSubmit () {
dispatch(submitSearch())
},
onShow () {
dispatch(showSearch())
},
const mapDispatchToProps = (dispatch) => ({
onChange: (value) => dispatch(changeSearch(value)),
onClear: () => dispatch(clearSearch()),
onSubmit: () => dispatch(submitSearch()),
onShow: () => dispatch(showSearch()),
})
export default

View File

@ -34,7 +34,7 @@ const messages = defineMessages({
donate: { id: 'tabs_bar.donate', defaultMessage: 'Make a Donation' },
})
const mapStateToProps = state => {
const mapStateToProps = (state) => {
const getAccount = makeGetAccount()
return {

View File

@ -8,7 +8,7 @@ import Icon from './icon'
import SidebarSectionItem from './sidebar_section_item'
import Text from './text'
const mapStateToProps = state => {
const mapStateToProps = (state) => {
const getAccount = makeGetAccount()
return {

View File

@ -117,8 +117,13 @@ export default class SidebarSectionItem extends PureComponent {
>
<div className={containerClasses}>
<div className={[_s.default]}>
{ icon && <Icon id={icon} className={iconClasses} width={iconSize} height={iconSize} /> }
{ image &&
{
icon &&
<Icon id={icon} className={iconClasses} width={iconSize} height={iconSize} />
}
{
image &&
<Image
alt={title}
className={_s.circle}
@ -128,10 +133,13 @@ export default class SidebarSectionItem extends PureComponent {
/>
}
</div>
<div className={[_s.default, _s.flexNormal, _s.px10, _s.textOverflowEllipsis, _s.overflowWrapBreakWord, _s.flexRow, _s.width100PC].join(' ')}>
<span className={textClasses}>{title}</span>
</div>
{ count > 0 &&
{
count > 0 &&
<span className={countClasses}>
{count}
</span>

View File

@ -3,21 +3,20 @@ import { injectIntl, defineMessages } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { HotKeys } from 'react-hotkeys';
import classNames from 'classnames/bind'
import { displayMedia } from '../../initial_state';
import StatusCard from '../status_card'
import { MediaGallery, Video } from '../../features/ui/util/async_components';
import ComposeFormContainer from '../../features/compose/containers/compose_form_container'
import RecursiveStatusContainer from '../../containers/recursive_status_container'
import StatusContent from '../status_content'
import StatusPrepend from '../status_prepend'
import StatusActionBar from '../status_action_bar';
import Poll from '../poll';
import StatusHeader from '../status_header'
import Text from '../text'
import { me, displayMedia } from '../initial_state';
import StatusCard from './status_card'
import { MediaGallery, Video } from '../features/ui/util/async_components';
import ComposeFormContainer from '../features/compose/containers/compose_form_container'
import StatusContent from './status_content'
import StatusPrepend from './status_prepend'
import StatusActionBar from './status_action_bar';
import Poll from './poll';
import StatusHeader from './status_header'
import Text from './text'
// We use the component (and not the container) since we do not want
// to use the progress bar to show download progress
import Bundle from '../../features/ui/util/bundle';
import Bundle from '../features/ui/util/bundle';
const cx = classNames.bind(_s)
@ -451,7 +450,7 @@ class Status extends ImmutablePureComponent {
}
{
!isChild &&
!isChild && !!me &&
<div className={[_s.default, _s.borderTop1PX, _s.borderColorSecondary, _s.pt10, _s.px15, _s.mb10].join(' ')}>
<ComposeFormContainer replyToId={status.get('id')} shouldCondense />
</div>

View File

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

View File

@ -1,254 +0,0 @@
.status {
position: relative;
min-height: 54px;
cursor: default;
margin-bottom: 10px;
border: 1px solid #171717;
@supports (-ms-overflow-style: -ms-autohiding-scrollbar) {
// Add margin to avoid Edge auto-hiding scrollbar appearing over content.
// On Edge 16 this is 16px and Edge <=15 it's 12px, so aim for 16px.
padding-right: 26px; // 10px + 16px
}
@keyframes fade {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
opacity: 1;
animation: fade 150ms linear;
.video-player {
margin-top: 8px;
}
&.light {
.status__relative-time {
color: $light-text-color;
}
.status__display-name {
color: $inverted-text-color;
}
.display-name {
strong {
color: $inverted-text-color;
}
span {
color: $light-text-color;
}
}
.status__content {
color: $inverted-text-color;
a {
color: $highlight-text-color;
}
a.status__content__spoiler-link {
color: $primary-text-color;
background: $ui-primary-color;
&:hover {
background: lighten($ui-primary-color, 8%);
}
}
}
}
&__meta {
font-size: 14px;
color: $gab-secondary-text;
a {
color: $gab-brand-default;
font-weight: bold;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}
@media screen and (min-width:630px) {
.status {
padding: 12px 15px 15px 78px;
min-height: 50px;
&__avatar {
left: 15px;
top: 17px;
}
&__content {
padding-top: 5px;
}
&__prepend {
margin-left: 78px;
padding-top: 15px;
}
&__prepend-icon-wrapper {
left: -32px;
}
.media-gallery,
.video-player {
margin-top: 10px;
}
}
}
.status__wrapper--filtered {
color: $dark-text-color;
border: 0;
margin: 0;
padding: 15px;
box-sizing: border-box;
width: 100%;
clear: both;
border-bottom: 1px solid lighten($ui-base-color, 8%);
@include text-sizing(inherit, 400, inherit, center);
}
.status__prepend-icon-wrapper {
left: -26px;
position: absolute;
}
.status__relative-time {
color: $dark-text-color;
font-size: 12px;
}
.status__display-name {
color: $dark-text-color;
}
.status__info {
display: flex;
flex-direction: column;
z-index: 4;
position: relative;
padding: 10px 10px 8px 62px;
&__dot-seperator {
font-size: 15px;
color: $dark-text-color;
@include horizontal-margin(5px);
}
&__attributes {
display: flex;
margin-top: 2px;
align-items: center;
&__item {
font-size: 12px;
color: $dark-text-color;
&--link {
cursor: pointer;
color: $primary-text-color;
&:hover {
text-decoration: underline;
}
}
}
}
&__actions {
display: flex;
&__icon {
margin-left: auto;
color: $dark-text-color;
}
}
}
.status__prepend {
margin-left: 68px;
color: $dark-text-color;
padding: 8px 0;
padding-bottom: 2px;
font-size: 14px;
position: relative;
.status__display-name strong {
color: $dark-text-color;
}
>span {
display: block;
@include text-overflow
}
}
.status__display-name {
strong {
color: $primary-text-color;
}
}
.status__avatar {
overflow: hidden;
@include circle(42px);
@include abs-position(10px, auto, auto, 10px);
}
.media-spoiler-video {
cursor: pointer;
margin-top: 8px;
position: relative;
border: 0;
display: block;
@include background-image("");
}
.media-spoiler-video-play-icon {
border-radius: 100px;
color: rgba($primary-text-color, 0.8);
font-size: 36px;
padding: 5px;
transform: translate(-50%, -50%);
@include abs-position(50%, auto, auto, 50%);
}
.media-spoiler {
background: $base-overlay-background;
color: $darker-text-color;
border: 0;
padding: 0;
border-radius: 4px;
appearance: none;
@include size(100%);
&:hover,
&:active,
&:focus {
padding: 0;
color: lighten($darker-text-color, 8%);
}
}

View File

@ -13,7 +13,10 @@ export default class StatusActionBarItem extends PureComponent {
icon: PropTypes.string.isRequired,
active: PropTypes.bool,
disabled: PropTypes.bool,
buttonRef: PropTypes.node,
buttonRef: PropTypes.oneOf([
PropTypes.func,
PropTypes.node,
]),
}
render() {

View File

@ -3,10 +3,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl'
import classNames from 'classnames/bind'
import { isRtl } from '../../utils/rtl'
import Button from '../button'
import Icon from '../icon'
import Text from '../text'
import { isRtl } from '../utils/rtl'
import Button from './button'
import Icon from './icon'
import Text from './text'
const MAX_HEIGHT = 200
@ -18,6 +18,12 @@ const messages = defineMessages({
const cx = classNames.bind(_s)
// .emojione {
// margin: -3px 0 0;
// @include size(20px);
// }
export default
@injectIntl
class StatusContent extends ImmutablePureComponent {
@ -167,7 +173,7 @@ class StatusContent extends ImmutablePureComponent {
const properContent = status.get('contentHtml')
return reblogContent
? `${reblogContent} <div class='status__quote'>${properContent}</div>`
? `${reblogContent} <div className='status__quote'>${properContent}</div>`
: properContent
}

View File

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

View File

@ -1,128 +0,0 @@
.status__content--with-action {
cursor: pointer;
}
.status__content {
position: relative;
padding-top: 2px;
color: $primary-text-color;
@include text-overflow(normal, break-word);
@include text-sizing(14px, 400, 20px);
@include horizontal-padding(10px);
&:focus {
outline: 0;
}
&.status__content--with-spoiler {
white-space: normal;
.status__content__text {
white-space: pre-wrap;
}
}
.emojione {
margin: -3px 0 0;
@include size(20px);
}
p {
margin-bottom: 20px;
white-space: pre-wrap;
&:last-child {
margin-bottom: 2px;
}
}
a {
color: $gab-brand-default;
text-decoration: none;
&:hover {
text-decoration: underline;
.fa {
color: lighten($dark-text-color, 7%);
}
}
&.mention {
&:hover {
text-decoration: none;
span {
text-decoration: underline;
}
}
}
.fa {
color: $dark-text-color;
}
}
.status__content__spoiler-link {
background: $action-button-color;
&:hover {
background: lighten($action-button-color, 7%);
text-decoration: none;
}
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus,
&:active {
outline: 0 !important;
}
}
.status__content__text {
display: none;
&.status__content__text--visible {
display: block;
}
}
}
.status__content.status__content--collapsed {
max-height: 20px * 15; // 15 lines is roughly above 500 characters
}
.status__content__read-more-button {
display: block;
color: $gab-brand-default;
border: 0;
background: transparent;
padding: 8px 0 0 0;
margin-left: 10px;
@include text-sizing(15px, 400, 20px);
&:hover,
&:active {
text-decoration: underline;
}
}
.status__content__spoiler-link {
display: inline-block;
border-radius: 2px;
background: transparent;
border: 0;
color: $inverted-text-color;
padding: 0 6px;
text-transform: uppercase;
cursor: pointer;
vertical-align: middle;
@include text-sizing(11px, 700, 20px);
}

View File

@ -1,13 +1,75 @@
import { Fragment } from 'react';
import { debounce } from 'lodash';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { createSelector } from 'reselect';
import sample from 'lodash.sample';
import debounce from 'lodash.debounce'
import { me, promotions } from '../initial_state';
import { dequeueTimeline } from '../actions/timelines';
import { scrollTopTimeline } from '../actions/timelines';
import { fetchStatus } from '../actions/statuses';
import StatusContainer from '../containers/status_container';
import ScrollableList from './scrollable_list';
import TimelineQueueButtonHeader from './timeline_queue_button_header';
import ColumnIndicator from './column_indicator';
export default class StatusList extends ImmutablePureComponent {
const makeGetStatusIds = () => createSelector([
(state, { type, id }) => state.getIn(['settings', type], ImmutableMap()),
(state, { type, id }) => state.getIn(['timelines', id, 'items'], ImmutableList()),
(state) => state.get('statuses'),
], (columnSettings, statusIds, statuses) => {
return statusIds.filter(id => {
if (id === null) return true;
const statusForId = statuses.get(id);
let showStatus = true;
if (columnSettings.getIn(['shows', 'reblog']) === false) {
showStatus = showStatus && statusForId.get('reblog') === null;
}
if (columnSettings.getIn(['shows', 'reply']) === false) {
showStatus = showStatus && (statusForId.get('in_reply_to_id') === null || statusForId.get('in_reply_to_account_id') === me);
}
return showStatus;
});
});
const mapStateToProps = (state, {timelineId}) => {
const getStatusIds = makeGetStatusIds();
const promotion = promotions.length > 0 && sample(promotions.filter(p => p.timeline_id === timelineId));
return {
statusIds: getStatusIds(state, { type: timelineId.substring(0,5) === 'group' ? 'group' : timelineId, id: timelineId }),
isLoading: state.getIn(['timelines', timelineId, 'isLoading'], true),
isPartial: state.getIn(['timelines', timelineId, 'isPartial'], false),
hasMore: state.getIn(['timelines', timelineId, 'hasMore']),
totalQueuedItemsCount: state.getIn(['timelines', timelineId, 'totalQueuedItemsCount']),
promotion: promotion,
promotedStatus: promotion && state.getIn(['statuses', promotion.status_id])
};
};
const mapDispatchToProps = (dispatch, ownProps) => ({
onDequeueTimeline(timelineId) {
dispatch(dequeueTimeline(timelineId, ownProps.onLoadMore));
},
onScrollToTop: debounce(() => {
dispatch(scrollTopTimeline(ownProps.timelineId, true));
}, 100),
onScroll: debounce(() => {
dispatch(scrollTopTimeline(ownProps.timelineId, false));
}, 100),
fetchStatus(id) {
dispatch(fetchStatus(id));
}
});
export default
@connect(mapStateToProps, mapDispatchToProps)
class StatusList extends ImmutablePureComponent {
static propTypes = {
scrollKey: PropTypes.string.isRequired,
@ -144,7 +206,7 @@ export default class StatusList extends ImmutablePureComponent {
contextType={timelineId}
showThread
/>
)).concat(scrollableContent);
)).concat(scrollableContent)
}
return (

View File

@ -1,42 +0,0 @@
import { injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import RelativeTimestamp from './relative_timestamp';
export default
@injectIntl
class StatusRevisionItem extends ImmutablePureComponent {
static propTypes = {
loading: PropTypes.bool.isRequired,
error: PropTypes.object,
data: PropTypes.array
};
render() {
const { loading, error, data } = this.props;
if (loading || !data) return null
if (error) {
return (
<div className='status-revisions-list'>
<div className='status-revisions-list__error'>An error occured</div>
</div>
)
}
return (
<div className='status-revisions-list'>
{data.map((revision, i) => (
<div key={i} className='status-revisions-list__item'>
<div className='status-revisions-list__item__timestamp'>
<RelativeTimestamp timestamp={revision.created_at} />
</div>
<div className='status-revisions-list__item__text'>{revision.text}</div>
</div>
))}
</div>
);
}
}

View File

@ -63,6 +63,7 @@ class TabBarItem extends PureComponent {
borderColorTransparent: !isActive,
borderColorBrand: isActive,
mr5: large,
mr2: !large,
})
const textParentClasses = cx({

View File

@ -11,11 +11,9 @@ const messages = defineMessages({
createPost: { id: 'column_header.create_post', defaultMessage: 'Create Post' },
})
const mapStateToProps = state => {
return {
const mapStateToProps = (state) => ({
account: state.getIn(['accounts', me]),
}
}
})
export default
@connect(mapStateToProps)
@ -57,7 +55,7 @@ class TimelineComposeBlock extends ImmutablePureComponent {
<Block>
<div className={[_s.default, _s.backgroundSubtle, _s.borderBottom1PX, _s.borderColorSecondary, _s.px15, _s.py2, _s.alignItemsCenter, _s.flexRow].join(' ')}>
<div className={_s.mr10}>
<Avatar account={account} size='20' />
<Avatar account={account} size={20} />
</div>
<Heading size='h5'>
{intl.formatMessage(messages.createPost)}

View File

@ -1,9 +1,11 @@
import { FormattedMessage } from 'react-intl'
import classNames from 'classnames'
import classNames from 'classnames/bind'
import { shortNumberFormat } from '../utils/numbers'
import Button from './button'
import Text from './text'
const cx = classNames.bind(_s)
export default class TimelineQueueButtonHeader extends PureComponent {
static propTypes = {
@ -23,17 +25,26 @@ export default class TimelineQueueButtonHeader extends PureComponent {
const hasItems = count > 0
// : todo :
const classes = classNames('timeline-queue-header', {
'timeline-queue-header--extended': hasItems,
const classes = cx({
default: 1,
positionFixed: 1,
displayNone: !hasItems,
top80PX: 1,
z4: 1,
center160PX: 1,
})
return (
<div className={classes}>
<a className='timeline-queue-header__btn' onClick={onClick}>
<Button
narrow
color='white'
backgroundColor='brand'
onClick={onClick}
>
{
hasItems &&
<Text color='inherit' size='small'>
<FormattedMessage
id='timeline_queue.label'
defaultMessage='{count} new {type}'
@ -42,8 +53,9 @@ export default class TimelineQueueButtonHeader extends PureComponent {
type: count === 1 ? itemType : `${itemType}s`,
}}
/>
</Text>
}
</a>
</Button>
</div>
)
}

View File

@ -11,6 +11,21 @@ const getDistance = (p1, p2) =>
const clamp = (min, max, value) => Math.min(max, Math.max(min, value));
// .zoomable-image {
// position: relative;
// @include flex(center, center);
// @include size(100%);
// img {
// object-fit: contain;
// @include size(auto);
// @include max-size($media-modal-media-max-width, $media-modal-media-max-height);
// }
// }
export default class ZoomableImage extends PureComponent {
static propTypes = {

View File

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

View File

@ -1,13 +0,0 @@
.zoomable-image {
position: relative;
@include flex(center, center);
@include size(100%);
img {
object-fit: contain;
@include size(auto);
@include max-size($media-modal-media-max-width, $media-modal-media-max-height);
}
}

View File

@ -1,68 +0,0 @@
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
import {
followAccount,
unfollowAccount,
blockAccount,
unblockAccount,
muteAccount,
unmuteAccount,
} from '../actions/accounts'
import { openModal } from '../actions/modal'
import { initMuteModal } from '../actions/mutes'
import { unfollowModal } from '../initial_state'
import { makeGetAccount } from '../selectors'
import Account from '../components/account'
const messages = defineMessages({
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
})
const makeMapStateToProps = () => {
const getAccount = makeGetAccount()
const mapStateToProps = (state, props) => ({
account: getAccount(state, props.id),
})
return mapStateToProps
}
const mapDispatchToProps = (dispatch, { intl }) => ({
onFollow (account) {
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
if (unfollowModal) {
dispatch(openModal('UNFOLLOW', {
accountId: account.get('id'),
}))
} else {
dispatch(unfollowAccount(account.get('id')))
}
} else {
dispatch(followAccount(account.get('id')))
}
},
onBlock (account) {
if (account.getIn(['relationship', 'blocking'])) {
dispatch(unblockAccount(account.get('id')))
} else {
dispatch(blockAccount(account.get('id')))
}
},
onMute (account) {
if (account.getIn(['relationship', 'muting'])) {
dispatch(unmuteAccount(account.get('id')))
} else {
dispatch(initMuteModal(account))
}
},
onMuteNotifications (account, notifications) {
dispatch(muteAccount(account.get('id'), notifications))
},
})
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Account))

View File

@ -1,18 +0,0 @@
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
import { unblockDomain } from '../actions/domain_blocks'
import { openModal } from '../actions/modal'
import Domain from '../components/domain'
const mapDispatchToProps = (dispatch, { intl }) => ({
onBlockDomain (domain) {
dispatch(openModal('BLOCK_DOMAIN', {
domain,
}))
},
onUnblockDomain (domain) {
dispatch(unblockDomain(domain))
},
})
export default injectIntl(connect(null, mapDispatchToProps)(Domain))

View File

@ -70,9 +70,11 @@ export default class GabSocial extends PureComponent {
};
componentDidMount() {
if (!!me) {
this.disconnect = store.dispatch(connectUserStream());
store.dispatch(connectStatusUpdateStream());
}
}
componentWillUnmount () {
if (this.disconnect) {

View File

@ -1,9 +0,0 @@
// import StatusContainer from './status_container'
// export default class RecursiveStatusContainer extends PureComponent {
// render() {
// return (
// <StatusContainer id={this.props.id} />
// )
// }
// }

View File

@ -1,64 +0,0 @@
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import { createSelector } from 'reselect';
import { sample } from 'lodash';
import debounce from 'lodash.debounce'
import { dequeueTimeline } from '../actions/timelines';
import { scrollTopTimeline } from '../actions/timelines';
import { fetchStatus } from '../actions/statuses';
import { me, promotions } from '../initial_state';
import StatusList from '../components/status_list';
const makeGetStatusIds = () => createSelector([
(state, { type, id }) => state.getIn(['settings', type], ImmutableMap()),
(state, { type, id }) => state.getIn(['timelines', id, 'items'], ImmutableList()),
(state) => state.get('statuses'),
], (columnSettings, statusIds, statuses) => {
return statusIds.filter(id => {
if (id === null) return true;
const statusForId = statuses.get(id);
let showStatus = true;
if (columnSettings.getIn(['shows', 'reblog']) === false) {
showStatus = showStatus && statusForId.get('reblog') === null;
}
if (columnSettings.getIn(['shows', 'reply']) === false) {
showStatus = showStatus && (statusForId.get('in_reply_to_id') === null || statusForId.get('in_reply_to_account_id') === me);
}
return showStatus;
});
});
const mapStateToProps = (state, {timelineId}) => {
const getStatusIds = makeGetStatusIds();
const promotion = promotions.length > 0 && sample(promotions.filter(p => p.timeline_id === timelineId));
return {
statusIds: getStatusIds(state, { type: timelineId.substring(0,5) === 'group' ? 'group' : timelineId, id: timelineId }),
isLoading: state.getIn(['timelines', timelineId, 'isLoading'], true),
isPartial: state.getIn(['timelines', timelineId, 'isPartial'], false),
hasMore: state.getIn(['timelines', timelineId, 'hasMore']),
totalQueuedItemsCount: state.getIn(['timelines', timelineId, 'totalQueuedItemsCount']),
promotion: promotion,
promotedStatus: promotion && state.getIn(['statuses', promotion.status_id])
};
};
const mapDispatchToProps = (dispatch, ownProps) => ({
onDequeueTimeline(timelineId) {
dispatch(dequeueTimeline(timelineId, ownProps.onLoadMore));
},
onScrollToTop: debounce(() => {
dispatch(scrollTopTimeline(ownProps.timelineId, true));
}, 100),
onScroll: debounce(() => {
dispatch(scrollTopTimeline(ownProps.timelineId, false));
}, 100),
fetchStatus(id) {
dispatch(fetchStatus(id));
}
});
export default connect(mapStateToProps, mapDispatchToProps)(StatusList);

View File

@ -41,7 +41,7 @@ class AccountGallery extends ImmutablePureComponent {
componentDidMount() {
const { accountId } = this.props
if (accountId) {
if (accountId && accountId !== -1) {
this.props.dispatch(expandAccountMediaTimeline(accountId))
}
}

View File

@ -3,7 +3,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes'
import debounce from 'lodash.debounce'
import { fetchBlocks, expandBlocks } from '../actions/blocks'
import AccountContainer from '../containers/account_container'
import Account from '../components/account'
import ColumnIndicator from '../components/column_indicator'
import ScrollableList from '../components/scrollable_list'
@ -11,7 +11,7 @@ const messages = defineMessages({
empty: { id: 'empty_column.blocks', defaultMessage: 'You haven\'t blocked any users yet.' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
accountIds: state.getIn(['user_lists', 'blocks', 'items']),
hasMore: !!state.getIn(['user_lists', 'blocks', 'next']),
})
@ -59,7 +59,7 @@ class Blocks extends ImmutablePureComponent {
>
{
accountIds.map(id =>
<AccountContainer key={`blocked-${id}`} id={id} compact />
<Account key={`blocked-${id}`} id={id} compact />
)
}
</ScrollableList>

View File

@ -26,7 +26,7 @@ const mapDispatchToProps = (dispatch) => ({
},
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
domains: state.getIn(['domain_lists', 'blocks', 'items']),
hasMore: !!state.getIn(['domain_lists', 'blocks', 'next']),
})

View File

@ -1,19 +1,15 @@
import { defineMessages, injectIntl } from 'react-intl'
import { expandCommunityTimeline } from '../actions/timelines'
import { connectCommunityStream } from '../actions/streaming'
import StatusListContainer from '../containers/status_list_container'
import StatusList from '../components/status_list'
const messages = defineMessages({
empty: { id: 'empty_column.community', defaultMessage: 'The community timeline is empty. Write something publicly to get the ball rolling!' },
})
const mapStateToProps = state => {
const onlyMedia = state.getIn(['settings', 'community', 'other', 'onlyMedia'])
return {
onlyMedia,
}
}
const mapStateToProps = (state) => ({
onlyMedia: state.getIn(['settings', 'community', 'other', 'onlyMedia'])
})
export default
@connect(mapStateToProps)
@ -67,7 +63,7 @@ class CommunityTimeline extends PureComponent {
const emptyMessage = intl.formatMessage(messages.empty)
return (
<StatusListContainer
<StatusList
scrollKey='community_timeline'
timelineId={`community${onlyMedia ? ':media' : ''}`}
onLoadMore={this.handleLoadMore}

View File

@ -270,7 +270,7 @@ class ComposeForm extends ImmutablePureComponent {
{
shouldCondense &&
<div className={[_s.default, _s.mr10, _s.mt5].join(' ')}>
<Avatar account={account} size='28' />
<Avatar account={account} size={28} />
</div>
}

View File

@ -6,11 +6,11 @@ const messages = defineMessages({
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
active: state.getIn(['popover', 'popoverType']) === 'EMOJI_PICKER',
})
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
onClick(targetRef) {
dispatch(openPopover('EMOJI_PICKER', {

View File

@ -10,7 +10,7 @@ const messages = defineMessages({
})
const makeMapStateToProps = () => {
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
acceptContentTypes: state.getIn(['media_attachments', 'accept_content_types']),
disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 3 || state.getIn(['compose', 'media_attachments']).some(m => m.get('type') === 'video')),
unavailable: state.getIn(['compose', 'poll']) !== null,
@ -20,10 +20,8 @@ const makeMapStateToProps = () => {
return mapStateToProps
}
const mapDispatchToProps = dispatch => ({
onSelectFile(files) {
dispatch(uploadCompose(files))
},
const mapDispatchToProps = (dispatch) => ({
onSelectFile: (files) => dispatch(uploadCompose(files)),
})
export default

View File

@ -22,7 +22,7 @@ const mapStateToProps = (state, { id, otherProps }) => {
}
}
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
onUndo: id => {
dispatch(undoUploadCompose(id));

View File

@ -5,11 +5,9 @@ import Avatar from '../../../../components/avatar';
import Button from '../../../../components/button'
import { me } from '../../../../initial_state';
const mapStateToProps = state => {
return {
const mapStateToProps = (state) => ({
account: state.getIn(['accounts', me]),
};
};
})
export default
@connect(mapStateToProps)

View File

@ -8,12 +8,12 @@ const messages = defineMessages({
remove_poll: { id: 'poll_button.remove_poll', defaultMessage: 'Remove poll' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
unavailable: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 0),
active: state.getIn(['compose', 'poll']) !== null,
})
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
onClick() {
dispatch((_, getState) => {

View File

@ -12,7 +12,7 @@ const mapStateToProps = (state) => ({
active: state.getIn(['compose', 'rte_controls_visible']),
})
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
onClick (status) {
dispatch(changeRichTextEditorControlsVisibility(status))

View File

@ -10,11 +10,11 @@ const messages = defineMessages({
schedule_status: { id: 'schedule_status.title', defaultMessage: 'Schedule' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
isPro: state.getIn(['accounts', me, 'is_pro']),
})
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
onOpenDatePickerPopover(targetRef) {
dispatch(openPopover('DATE_PICKER', {
targetRef,

View File

@ -10,8 +10,7 @@ import Block from '../../../../components/block'
import Heading from '../../../../components/heading'
import Button from '../../../../components/button'
import Text from '../../../../components/text'
import AccountContainer from '../../../../containers/account_container'
import Account from '../../../../components/account'
export default class SearchResults extends ImmutablePureComponent {
@ -65,7 +64,7 @@ export default class SearchResults extends ImmutablePureComponent {
</div>
{
results.get('accounts').slice(0, size).map(accountId => <AccountContainer expanded key={accountId} id={accountId} />)
results.get('accounts').slice(0, size).map(accountId => <Account expanded key={accountId} id={accountId} />)
}
</div>
);

View File

@ -6,12 +6,12 @@ const messages = defineMessages({
markAsSensitive: { id: 'compose_form.sensitive.hide', defaultMessage: 'Mark media as sensitive' },
})
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
active: state.getIn(['compose', 'sensitive']),
disabled: state.getIn(['compose', 'spoiler']),
})
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
onClick () {
dispatch(changeComposeSensitivity())

View File

@ -12,7 +12,7 @@ const mapStateToProps = (state) => ({
active: state.getIn(['compose', 'spoiler']),
})
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
onClick () {
dispatch(changeComposeSpoilerness())

View File

@ -4,7 +4,7 @@ import ProgressBar from '../../../../components/progress_bar'
import Upload from '../media_upload_item'
import SensitiveMediaButton from '../sensitive_media_button'
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
mediaIds: state.getIn(['compose', 'media_attachments']).map(item => item.get('id')),
isUploading: state.getIn(['compose', 'is_uploading']),
uploadProgress: state.getIn(['compose', 'progress']),

Some files were not shown because too many files have changed in this diff Show More