Progress
This commit is contained in:
parent
b5e3c2a94f
commit
bb4fcdf32d
10
.eslintrc.js
10
.eslintrc.js
|
@ -10,6 +10,13 @@ module.exports = {
|
|||
|
||||
globals: {
|
||||
ATTACHMENT_HOST: false,
|
||||
_s: true,
|
||||
PropTypes: true,
|
||||
PureComponent: true,
|
||||
React: {
|
||||
Component: true,
|
||||
},
|
||||
connect: true,
|
||||
},
|
||||
|
||||
parser: 'babel-eslint',
|
||||
|
@ -98,8 +105,9 @@ module.exports = {
|
|||
classes: 'always',
|
||||
},
|
||||
],
|
||||
'prefer-const': 'error',
|
||||
quotes: ['error', 'single'],
|
||||
semi: 'error',
|
||||
semi: 'off',
|
||||
strict: 'off',
|
||||
'valid-typeof': 'error',
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import api from '../api';
|
||||
import { CancelToken, isCancel } from 'axios';
|
||||
import { throttle } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import throttle from 'lodash.throttle'
|
||||
import { search as emojiSearch } from '../components/emoji/emoji_mart_search_light';
|
||||
import { urlRegex } from '../features/compose/util/url_regex'
|
||||
import { tagHistory } from '../settings';
|
||||
|
@ -133,7 +132,7 @@ export function mentionCompose(account, routerHistory) {
|
|||
export function handleComposeSubmit(dispatch, getState, response, status) {
|
||||
if (!dispatch || !getState) return;
|
||||
|
||||
const isScheduledStatus = response.data['scheduled_at'] !== undefined;
|
||||
const isScheduledStatus = response.data.scheduled_at !== undefined;
|
||||
if (isScheduledStatus) {
|
||||
// dispatch(showAlertForError({
|
||||
// response: {
|
||||
|
@ -154,7 +153,7 @@ export function handleComposeSubmit(dispatch, getState, response, status) {
|
|||
const timeline = getState().getIn(['timelines', timelineId]);
|
||||
|
||||
if (timeline && timeline.get('items').size > 0 && timeline.getIn(['items', 0]) !== null && timeline.get('online')) {
|
||||
let dequeueArgs = {};
|
||||
const dequeueArgs = {};
|
||||
if (timelineId === 'community') dequeueArgs.onlyMedia = getState().getIn(['settings', 'community', 'other', 'onlyMedia']);
|
||||
dispatch(dequeueTimeline(timelineId, null, dequeueArgs));
|
||||
dispatch(updateTimeline(timelineId, { ...response.data }));
|
||||
|
@ -174,7 +173,7 @@ export function submitCompose(routerHistory, group) {
|
|||
if (!me) return;
|
||||
|
||||
let status = getState().getIn(['compose', 'text'], '');
|
||||
let statusMarkdown = getState().getIn(['compose', 'text_markdown'], '');
|
||||
const statusMarkdown = getState().getIn(['compose', 'text_markdown'], '');
|
||||
const media = getState().getIn(['compose', 'media_attachments']);
|
||||
|
||||
// : hack :
|
||||
|
@ -183,10 +182,10 @@ export function submitCompose(routerHistory, group) {
|
|||
const hasProtocol = match.startsWith('https://') || match.startsWith('http://')
|
||||
return hasProtocol ? match : `http://${match}`
|
||||
})
|
||||
statusMarkdown = statusMarkdown.replace(urlRegex, (match) =>{
|
||||
const hasProtocol = match.startsWith('https://') || match.startsWith('http://')
|
||||
return hasProtocol ? match : `http://${match}`
|
||||
})
|
||||
// statusMarkdown = statusMarkdown.replace(urlRegex, (match) =>{
|
||||
// const hasProtocol = match.startsWith('https://') || match.startsWith('http://')
|
||||
// return hasProtocol ? match : `http://${match}`
|
||||
// })
|
||||
|
||||
dispatch(submitComposeRequest());
|
||||
dispatch(closeModal());
|
||||
|
@ -197,12 +196,13 @@ export function submitCompose(routerHistory, group) {
|
|||
: `/api/v1/statuses/${id}`;
|
||||
const method = id === null ? 'post' : 'put';
|
||||
|
||||
let scheduled_at = getState().getIn(['compose', 'scheduled_at'], null);
|
||||
if (scheduled_at !== null) scheduled_at = moment.utc(scheduled_at).toDate();
|
||||
const scheduled_at = getState().getIn(['compose', 'scheduled_at'], null);
|
||||
// : todo :
|
||||
// if (scheduled_at !== null) scheduled_at = moment.utc(scheduled_at).toDate();
|
||||
|
||||
api(getState)[method](endpoint, {
|
||||
status,
|
||||
statusMarkdown,
|
||||
// statusMarkdown,
|
||||
scheduled_at,
|
||||
in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
|
||||
quote_of_id: getState().getIn(['compose', 'quote_of_id'], null),
|
||||
|
|
|
@ -16,7 +16,6 @@ import { me } from '../initial_state';
|
|||
|
||||
export const NOTIFICATIONS_INITIALIZE = 'NOTIFICATIONS_INITIALIZE';
|
||||
export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE';
|
||||
export const NOTIFICATIONS_UPDATE_NOOP = 'NOTIFICATIONS_UPDATE_NOOP';
|
||||
export const NOTIFICATIONS_UPDATE_QUEUE = 'NOTIFICATIONS_UPDATE_QUEUE';
|
||||
export const NOTIFICATIONS_DEQUEUE = 'NOTIFICATIONS_DEQUEUE';
|
||||
|
||||
|
@ -76,7 +75,6 @@ export function updateNotificationsQueue(notification, intlMessages, intlLocale,
|
|||
return (dispatch, getState) => {
|
||||
const showAlert = getState().getIn(['settings', 'notifications', 'alerts', notification.type], true);
|
||||
const filters = getFilters(getState(), { contextType: 'notifications' });
|
||||
const playSound = getState().getIn(['settings', 'notifications', 'sounds', notification.type], true);
|
||||
|
||||
let filtered = false;
|
||||
|
||||
|
@ -101,13 +99,6 @@ export function updateNotificationsQueue(notification, intlMessages, intlLocale,
|
|||
});
|
||||
}
|
||||
|
||||
if (playSound && !filtered) {
|
||||
dispatch({
|
||||
type: NOTIFICATIONS_UPDATE_NOOP,
|
||||
meta: { sound: 'ribbit' },
|
||||
});
|
||||
}
|
||||
|
||||
if (isOnNotificationsPage) {
|
||||
dispatch({
|
||||
type: NOTIFICATIONS_UPDATE_QUEUE,
|
||||
|
@ -115,8 +106,7 @@ export function updateNotificationsQueue(notification, intlMessages, intlLocale,
|
|||
intlMessages,
|
||||
intlLocale,
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
dispatch(updateNotifications(notification, intlMessages, intlLocale));
|
||||
}
|
||||
}
|
||||
|
@ -127,15 +117,13 @@ export function dequeueNotifications() {
|
|||
const queuedNotifications = getState().getIn(['notifications', 'queuedNotifications'], ImmutableList());
|
||||
const totalQueuedNotificationsCount = getState().getIn(['notifications', 'totalQueuedNotificationsCount'], 0);
|
||||
|
||||
if (totalQueuedNotificationsCount == 0) {
|
||||
if (totalQueuedNotificationsCount === 0) {
|
||||
return;
|
||||
}
|
||||
else if (totalQueuedNotificationsCount > 0 && totalQueuedNotificationsCount <= MAX_QUEUED_NOTIFICATIONS) {
|
||||
} else if (totalQueuedNotificationsCount > 0 && totalQueuedNotificationsCount <= MAX_QUEUED_NOTIFICATIONS) {
|
||||
queuedNotifications.forEach(block => {
|
||||
dispatch(updateNotifications(block.notification, block.intlMessages, block.intlLocale));
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
dispatch(expandNotifications());
|
||||
}
|
||||
|
||||
|
@ -168,9 +156,9 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log("activeFilter:", activeFilter)
|
||||
console.log("excludeTypesFromSettings(getState()):", excludeTypesFromSettings(getState()))
|
||||
console.log("excludeTypesFromFilter(activeFilter):", excludeTypesFromFilter(activeFilter))
|
||||
console.log('activeFilter:', activeFilter)
|
||||
console.log('excludeTypesFromSettings(getState()):', excludeTypesFromSettings(getState()))
|
||||
console.log('excludeTypesFromFilter(activeFilter):', excludeTypesFromFilter(activeFilter))
|
||||
|
||||
// : todo :
|
||||
// filter verified and following here too
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import api from '../api';
|
||||
import { debounce } from 'lodash';
|
||||
import debounce from 'lodash.debounce';
|
||||
// import { showAlertForError } from './alerts';
|
||||
import { me } from '../initial_state';
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ export const fetchGifCategories = () => {
|
|||
}
|
||||
}
|
||||
|
||||
export const fetchGifResults = () => {
|
||||
export const fetchGifResults = (maxId) => {
|
||||
return function (dispatch, getState) {
|
||||
if (!me) return
|
||||
|
||||
|
@ -39,7 +39,7 @@ export const fetchGifResults = () => {
|
|||
|
||||
axios.get(`https://api.tenor.com/v1/search?q=${searchText}&media_filter=minimal&limit=30&key=${tenorkey}`)
|
||||
.then((response) => {
|
||||
console.log("response:", response)
|
||||
console.log('response:', response)
|
||||
dispatch(fetchGifResultsSuccess(response.data.results))
|
||||
}).catch(function (error) {
|
||||
dispatch(fetchGifResultsFail(error))
|
||||
|
|
|
@ -55,29 +55,24 @@ export function dequeueTimeline(timeline, expandFunc, optionalExpandArgs) {
|
|||
|
||||
let shouldDispatchDequeue = true;
|
||||
|
||||
if (totalQueuedItemsCount == 0) {
|
||||
if (totalQueuedItemsCount === 0) {
|
||||
return;
|
||||
}
|
||||
else if (totalQueuedItemsCount > 0 && totalQueuedItemsCount <= MAX_QUEUED_ITEMS) {
|
||||
} else if (totalQueuedItemsCount > 0 && totalQueuedItemsCount <= MAX_QUEUED_ITEMS) {
|
||||
queuedItems.forEach(status => {
|
||||
dispatch(updateTimeline(timeline, status.toJS(), null));
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (typeof expandFunc === 'function') {
|
||||
dispatch(clearTimeline(timeline));
|
||||
expandFunc();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (timeline === 'home') {
|
||||
dispatch(clearTimeline(timeline));
|
||||
dispatch(expandHomeTimeline(optionalExpandArgs));
|
||||
}
|
||||
else if (timeline === 'community') {
|
||||
} else if (timeline === 'community') {
|
||||
dispatch(clearTimeline(timeline));
|
||||
dispatch(expandCommunityTimeline(optionalExpandArgs));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
shouldDispatchDequeue = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ export const getLinks = response => {
|
|||
return LinkHeader.parse(value);
|
||||
};
|
||||
|
||||
let csrfHeader = {};
|
||||
const csrfHeader = {};
|
||||
|
||||
function setCSRFHeader() {
|
||||
const csrfToken = document.querySelector('meta[name=csrf-token]');
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
const HiddenIcon = ({
|
||||
className = '',
|
||||
width = '16px',
|
||||
height = '16px',
|
||||
viewBox = '0 0 48 48',
|
||||
title = 'Hidden',
|
||||
}) => (
|
||||
<svg
|
||||
className={className}
|
||||
version='1.1'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
x='0px'
|
||||
y='0px'
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox={viewBox}
|
||||
xmlSpace='preserve'
|
||||
aria-label={title}
|
||||
>
|
||||
<g>
|
||||
<path d='M 23.632812 16.398438 L 30.503906 23.269531 L 30.539062 22.910156 C 30.539062 19.300781 27.605469 16.367188 23.996094 16.367188 Z M 23.632812 16.398438' />
|
||||
<path d='M 23.996094 12.003906 C 30.015625 12.003906 34.902344 16.890625 34.902344 22.910156 C 34.902344 24.316406 34.617188 25.65625 34.125 26.890625 L 40.507812 33.269531 C 43.800781 30.523438 46.398438 26.964844 48 22.910156 C 44.214844 13.332031 34.914062 6.550781 23.996094 6.550781 C 20.941406 6.550781 18.019531 7.09375 15.300781 8.078125 L 20.015625 12.777344 C 21.246094 12.296875 22.585938 12.003906 23.996094 12.003906 Z M 23.996094 12.003906' />
|
||||
<path d='M 2.179688 6.058594 L 7.15625 11.03125 L 8.148438 12.023438 C 4.546875 14.839844 1.703125 18.578125 0 22.910156 C 3.773438 32.484375 13.089844 39.269531 23.996094 39.269531 C 27.375 39.269531 30.605469 38.613281 33.558594 37.425781 L 34.488281 38.351562 L 40.84375 44.722656 L 43.625 41.953125 L 4.960938 3.277344 Z M 14.242188 18.109375 L 17.613281 21.480469 C 17.515625 21.949219 17.449219 22.417969 17.449219 22.910156 C 17.449219 26.519531 20.382812 29.453125 23.996094 29.453125 C 24.484375 29.453125 24.953125 29.386719 25.414062 29.289062 L 28.78125 32.660156 C 27.332031 33.378906 25.71875 33.816406 23.996094 33.816406 C 17.972656 33.816406 13.089844 28.929688 13.089844 22.910156 C 13.089844 21.1875 13.523438 19.570312 14.242188 18.109375 Z M 14.242188 18.109375' />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default HiddenIcon
|
|
@ -93,6 +93,7 @@ class Account extends ImmutablePureComponent {
|
|||
)
|
||||
}
|
||||
|
||||
// : todo : cleanup
|
||||
let buttonOptions
|
||||
let buttonText
|
||||
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
import unicodeMapping from '../emoji/emoji_unicode_mapping_light';
|
||||
import unicodeMapping from '../emoji/emoji_unicode_mapping_light'
|
||||
|
||||
const assetHost = process.env.CDN_HOST || '';
|
||||
const assetHost = process.env.CDN_HOST || ''
|
||||
|
||||
export default class AutosuggestEmoji extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
emoji: PropTypes.object.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const { emoji } = this.props;
|
||||
let url;
|
||||
const { emoji } = this.props
|
||||
let url
|
||||
|
||||
if (emoji.custom) {
|
||||
url = emoji.imageUrl;
|
||||
url = emoji.imageUrl
|
||||
} else {
|
||||
const mapping = unicodeMapping[emoji.native] || unicodeMapping[emoji.native.replace(/\uFE0F$/, '')];
|
||||
const mapping = unicodeMapping[emoji.native] || unicodeMapping[emoji.native.replace(/\uFE0F$/, '')]
|
||||
|
||||
if (!mapping) return null;
|
||||
if (!mapping) return null
|
||||
|
||||
url = `${assetHost}/emoji/${mapping.filename}.svg`;
|
||||
url = `${assetHost}/emoji/${mapping.filename}.svg`
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -27,7 +27,7 @@ export default class AutosuggestEmoji extends PureComponent {
|
|||
<img className='emojione' src={url} alt={emoji.native || emoji.colons} />
|
||||
{emoji.colons}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ import { Fragment } from 'react'
|
|||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import classNames from 'classnames/bind'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import Textarea from 'react-textarea-autosize'
|
||||
import ContentEditable from 'react-contenteditable'
|
||||
import { isRtl } from '../../utils/rtl'
|
||||
import { textAtCursorMatchesToken } from '../../utils/cursor_token_match'
|
||||
import AutosuggestAccount from '../autosuggest_account'
|
||||
|
@ -210,7 +208,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
|||
id,
|
||||
maxLength,
|
||||
textarea,
|
||||
prependIcon
|
||||
prependIcon,
|
||||
} = this.props
|
||||
|
||||
const { suggestionsHidden } = this.state
|
||||
|
@ -307,6 +305,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
|||
</div>
|
||||
{children}
|
||||
</div>
|
||||
{ /* : todo : */ }
|
||||
<div className='autosuggest-textarea__suggestions-wrapper'>
|
||||
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
|
||||
{suggestions.map(this.renderSuggestion)}
|
||||
|
|
|
@ -47,6 +47,7 @@ class Avatar extends ImmutablePureComponent {
|
|||
const shouldAnimate = animate || !sameImg
|
||||
|
||||
const options = {
|
||||
alt: !account ? 'Avatar' : account.get('display_name'),
|
||||
className: [_s.default, _s.circle, _s.overflowHidden].join(' '),
|
||||
onMouseEnter: shouldAnimate ? this.handleMouseEnter : undefined,
|
||||
onMouseLeave: shouldAnimate ? this.handleMouseLeave : undefined,
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
export default class Block extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children } = this.props
|
||||
|
||||
|
@ -8,4 +13,5 @@ export default class Block extends PureComponent {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -32,7 +32,7 @@ export default class ColumnHeader extends PureComponent {
|
|||
title,
|
||||
showBackBtn,
|
||||
tabs,
|
||||
actions
|
||||
actions,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
|
@ -68,15 +68,15 @@ export default class ColumnHeader extends PureComponent {
|
|||
{
|
||||
actions.map((action, i) => (
|
||||
<Button
|
||||
radiusSmall
|
||||
backgroundColor='tertiary'
|
||||
backgroundColor='none'
|
||||
color='secondary'
|
||||
onClick={() => action.onClick()}
|
||||
key={`column-header-action-btn-${i}`}
|
||||
className={[_s.ml5, _s.px10].join(' ')}
|
||||
iconClassName={_s.fillColorSecondary}
|
||||
className={[_s.ml5, _s.fillColorBrand_onHover, _s.backgroundColorBrandLightOpaque_onHover, _s.px10].join(' ')}
|
||||
icon={action.icon}
|
||||
iconWidth='20px'
|
||||
iconHeight='20px'
|
||||
iconClassName={_s.inheritFill}
|
||||
iconWidth='15px'
|
||||
iconHeight='15px'
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
|
|
@ -22,33 +22,9 @@ const makeMapStateToProps = () => {
|
|||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const status = getStatus(state, props)
|
||||
let descendantsIds = Immutable.List()
|
||||
|
||||
if (status) {
|
||||
// ALL descendants
|
||||
descendantsIds = descendantsIds.withMutations(mutable => {
|
||||
const ids = [status.get('id')]
|
||||
|
||||
while (ids.length > 0) {
|
||||
let id = ids.shift();
|
||||
const replies = state.getIn(['contexts', 'replies', id])
|
||||
|
||||
if (status.get('id') !== id) {
|
||||
mutable.push(id)
|
||||
}
|
||||
|
||||
if (replies) {
|
||||
replies.reverse().forEach(reply => {
|
||||
ids.unshift(reply)
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
status,
|
||||
descendantsIds,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,30 +38,22 @@ class Comment extends ImmutablePureComponent {
|
|||
|
||||
static propTypes = {
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
descendantsIds: ImmutablePropTypes.list,
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
// if (this.props.onClick) {
|
||||
// this.props.onClick();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (!this.context.router) return;
|
||||
|
||||
// this.context.router.history.push(
|
||||
// `/${this._properStatus().getIn(['account', 'acct'])}/posts/${this._properStatus().get('id')}`
|
||||
// )
|
||||
indent: ImmutablePropTypes.number,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { status } = this.props
|
||||
const { status, indent } = this.props
|
||||
|
||||
console.log("status:", status)
|
||||
const style = {
|
||||
paddingLeft: `${indent * 40}px`,
|
||||
}
|
||||
|
||||
// : todo : add media
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.px10, _s.mb10, _s.py5].join(' ')} data-comment={status.get('id')}>
|
||||
<div className={[_s.default].join(' ')}>
|
||||
<div className={[_s.default].join(' ')} style={style}>
|
||||
|
||||
<div className={[_s.default, _s.flexRow].join(' ')}>
|
||||
<NavLink
|
||||
|
|
|
@ -1,159 +1,27 @@
|
|||
import { Fragment } from 'react'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { makeGetStatus } from '../selectors';
|
||||
import CommentHeader from './comment_header'
|
||||
import Avatar from './avatar'
|
||||
import Button from './button'
|
||||
import DisplayName from './display_name'
|
||||
import DotTextSeperator from './dot_text_seperator'
|
||||
import RelativeTimestamp from './relative_timestamp'
|
||||
import Text from './text'
|
||||
import StatusContent from './status_content'
|
||||
import Comment from './comment'
|
||||
|
||||
const messages = defineMessages({
|
||||
follow: { id: 'follow', defaultMessage: 'Follow' },
|
||||
})
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getStatus = makeGetStatus()
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const status = getStatus(state, props)
|
||||
let descendantsIds = Immutable.List()
|
||||
|
||||
if (status) {
|
||||
// ALL descendants
|
||||
descendantsIds = descendantsIds.withMutations(mutable => {
|
||||
const ids = [status.get('id')]
|
||||
|
||||
while (ids.length > 0) {
|
||||
let id = ids.shift();
|
||||
const replies = state.getIn(['contexts', 'replies', id])
|
||||
|
||||
if (status.get('id') !== id) {
|
||||
mutable.push(id)
|
||||
}
|
||||
|
||||
if (replies) {
|
||||
replies.reverse().forEach(reply => {
|
||||
ids.unshift(reply)
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
status,
|
||||
descendantsIds,
|
||||
}
|
||||
}
|
||||
|
||||
return mapStateToProps
|
||||
}
|
||||
|
||||
export default
|
||||
@injectIntl
|
||||
@connect(makeMapStateToProps)
|
||||
class Comment extends ImmutablePureComponent {
|
||||
export default class CommentList extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
descendantsIds: ImmutablePropTypes.list,
|
||||
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
// if (this.props.onClick) {
|
||||
// this.props.onClick();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (!this.context.router) return;
|
||||
|
||||
// this.context.router.history.push(
|
||||
// `/${this._properStatus().getIn(['account', 'acct'])}/posts/${this._properStatus().get('id')}`
|
||||
// )
|
||||
descendants: ImmutablePropTypes.list,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { status } = this.props
|
||||
|
||||
console.log("status:", status)
|
||||
const { descendants } = this.props
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.px10, _s.mb10, _s.py5].join(' ')} data-comment={status.get('id')}>
|
||||
<div className={[_s.default].join(' ')}>
|
||||
|
||||
<div className={[_s.default, _s.flexRow].join(' ')}>
|
||||
<NavLink
|
||||
to={`/${status.getIn(['account', 'acct'])}`}
|
||||
title={status.getIn(['account', 'acct'])}
|
||||
className={[_s.default, _s.mr10, _s.pt5].join(' ')}
|
||||
>
|
||||
<Avatar account={status.get('account')} size={32} />
|
||||
</NavLink>
|
||||
|
||||
<div className={[_s.default, _s.flexGrow1].join(' ')}>
|
||||
<div className={[_s.default, _s.px10, _s.py5, _s.radiusSmall, _s.backgroundSubtle].join(' ')}>
|
||||
<div className={_s.pt2}>
|
||||
<CommentHeader status={status} />
|
||||
</div>
|
||||
<div className={[_s.py5].join(' ')}>
|
||||
<StatusContent
|
||||
status={status}
|
||||
onClick={this.handleClick}
|
||||
isComment
|
||||
collapsable
|
||||
<div>
|
||||
{
|
||||
descendants.map((descendant, i) => (
|
||||
<Comment
|
||||
key={`comment-${descendant.get('statusId')}-${i}`}
|
||||
id={descendant.get('statusId')}
|
||||
indent={descendant.get('indent')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={[_s.default, _s.flexRow, _s.mt5].join(' ')}>
|
||||
|
||||
<Button
|
||||
text
|
||||
radiusSmall
|
||||
backgroundColor='none'
|
||||
color='tertiary'
|
||||
className={[_s.px5, _s.backgroundSubtle_onHover, _s.py2, _s.mr5].join(' ')}
|
||||
>
|
||||
<Text size='extraSmall' color='inherit' weight='bold'>
|
||||
Like
|
||||
</Text>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
text
|
||||
radiusSmall
|
||||
backgroundColor='none'
|
||||
color='tertiary'
|
||||
className={[_s.px5, _s.backgroundSubtle_onHover, _s.py2, _s.mr5].join(' ')}
|
||||
>
|
||||
<Text size='extraSmall' color='inherit' weight='bold'>
|
||||
Reply
|
||||
</Text>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
text
|
||||
radiusSmall
|
||||
backgroundColor='none'
|
||||
color='tertiary'
|
||||
className={[_s.px5, _s.backgroundSubtle_onHover, _s.py2, _s.mr5].join(' ')}
|
||||
>
|
||||
<Text size='extraSmall' color='inherit' weight='bold'>
|
||||
···
|
||||
</Text>
|
||||
</Button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { debounce } from 'lodash'
|
||||
import debounce from 'lodash.debounce'
|
||||
import classNames from 'classnames/bind'
|
||||
import { openPopover, closePopover } from '../actions/popover'
|
||||
import Icon from './icon'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { pick } from 'lodash';
|
||||
import pick from 'lodash.pick'
|
||||
import { emojiIndex } from 'emoji-mart';
|
||||
import { search } from '../emoji_mart_search_light';
|
||||
|
||||
|
|
|
@ -40,17 +40,6 @@ export default class FileInput extends PureComponent {
|
|||
} = this.props
|
||||
const { file } = this.state
|
||||
|
||||
const imageClasses = cx({
|
||||
border2PX: 1,
|
||||
borderDashed: 1,
|
||||
borderColorSecondary: 1,
|
||||
backgroundColorPrimary: 1,
|
||||
px10: 1,
|
||||
py10: 1,
|
||||
radiusSmall: 1,
|
||||
cursorPointer: 1,
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
|
@ -63,7 +52,7 @@ export default class FileInput extends PureComponent {
|
|||
}
|
||||
|
||||
<label
|
||||
className={[_s.default, _s.alignItemsCenter, _s.justifyContentCenter].join(' ')}
|
||||
className={[_s.default, _s.alignItemsCenter, _s.radiusSmall, _s.cursorPointer, _s.px10, _s.py10, _s.justifyContentCenter, _s.border2PX, _s.borderColorSecondary, _s.borderDashed].join(' ')}
|
||||
htmlFor={`file-input-${title}`}
|
||||
style={{
|
||||
width,
|
||||
|
@ -71,9 +60,7 @@ export default class FileInput extends PureComponent {
|
|||
}}
|
||||
>
|
||||
<Image
|
||||
className={imageClasses}
|
||||
width={width}
|
||||
height={height}
|
||||
className={[_s.height100PC, _s.width100PC, _s.radiusSmall].join(' ')}
|
||||
src={fileType === 'image' ? file : null}
|
||||
/>
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Icon from './icon'
|
||||
import Button from './button'
|
||||
|
||||
export default class FloatingActionButton extends Component {
|
||||
export default class FloatingActionButton extends PureComponent {
|
||||
static propTypes = {
|
||||
onClick: PropTypes.func.isRequired,
|
||||
message: PropTypes.string.isRequired,
|
||||
|
|
|
@ -30,6 +30,7 @@ export default
|
|||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class GroupCollectionItem extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
group: ImmutablePropTypes.map,
|
||||
relationships: ImmutablePropTypes.map,
|
||||
|
@ -50,14 +51,9 @@ class GroupCollectionItem extends ImmutablePureComponent {
|
|||
</Fragment>
|
||||
) : intl.formatMessage(messages.no_recent_activity)
|
||||
|
||||
const imageHeight = '180px'
|
||||
|
||||
const isMember = relationships.get('member')
|
||||
|
||||
const outsideClasses = cx({
|
||||
default: 1,
|
||||
width50PC: 1,
|
||||
})
|
||||
const isAdmin = relationships.get('admin')
|
||||
const coverSrc = group.get('cover')
|
||||
|
||||
const navLinkClasses = cx({
|
||||
default: 1,
|
||||
|
@ -74,18 +70,30 @@ class GroupCollectionItem extends ImmutablePureComponent {
|
|||
})
|
||||
|
||||
return (
|
||||
<div className={outsideClasses}>
|
||||
<div className={_s.default}>
|
||||
<NavLink
|
||||
to={`/groups/${group.get('id')}`}
|
||||
className={navLinkClasses}
|
||||
>
|
||||
{
|
||||
!!coverSrc &&
|
||||
<Image
|
||||
src={group.get('cover')}
|
||||
src={coverSrc}
|
||||
alt={group.get('title')}
|
||||
height={imageHeight}
|
||||
className={_s.height158PX}
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
!coverSrc && (isMember || isAdmin) &&
|
||||
<div className={[_s.default, _s.height40PX, _s.backgroundSubtle, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')} />
|
||||
}
|
||||
|
||||
{
|
||||
(isMember || isAdmin) &&
|
||||
<div className={[_s.default, _s.flexRow, _s.positionAbsolute, _s.top0, _s.right0, _s.pt10, _s.mr10].join(' ')}>
|
||||
{
|
||||
isMember &&
|
||||
<Text
|
||||
badge
|
||||
className={_s.backgroundColorWhite}
|
||||
|
@ -94,6 +102,9 @@ class GroupCollectionItem extends ImmutablePureComponent {
|
|||
>
|
||||
{intl.formatMessage(messages.member)}
|
||||
</Text>
|
||||
}
|
||||
{
|
||||
isAdmin &&
|
||||
<Text
|
||||
badge
|
||||
className={[_s.backgroundColorBlack, _s.ml5].join(' ')}
|
||||
|
@ -102,7 +113,9 @@ class GroupCollectionItem extends ImmutablePureComponent {
|
|||
>
|
||||
{intl.formatMessage(messages.admin)}
|
||||
</Text>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div className={[_s.default, _s.px10, _s.my10].join(' ')}>
|
||||
<Text color='primary' size='medium' weight='bold'>
|
||||
|
@ -119,8 +132,6 @@ class GroupCollectionItem extends ImmutablePureComponent {
|
|||
<Text color='secondary' size='small' className={_s.ml5}>
|
||||
{subtitle}
|
||||
</Text>
|
||||
<DotTextSeperator />
|
||||
<Text color='secondary' size='small' className={_s.ml5}>→</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -128,4 +139,5 @@ class GroupCollectionItem extends ImmutablePureComponent {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -25,6 +25,7 @@ export default
|
|||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class GroupListItem extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
group: ImmutablePropTypes.map,
|
||||
relationships: ImmutablePropTypes.map,
|
||||
|
@ -82,16 +83,22 @@ class GroupListItem extends ImmutablePureComponent {
|
|||
mb10: !slim,
|
||||
})
|
||||
|
||||
const coverSrc = group.get('cover')
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
to={`/groups/${group.get('id')}`}
|
||||
className={containerClasses}
|
||||
>
|
||||
|
||||
{
|
||||
(!!coverSrc || slim) &&
|
||||
<Image
|
||||
src={group.get('cover')}
|
||||
src={coverSrc}
|
||||
alt={group.get('title')}
|
||||
className={imageClasses}
|
||||
/>
|
||||
}
|
||||
|
||||
<div className={textContainerClasses}>
|
||||
<Text color='brand' weight='bold'>
|
||||
|
@ -115,4 +122,5 @@ class GroupListItem extends ImmutablePureComponent {
|
|||
</NavLink>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -45,6 +45,7 @@ export default class HashtagItem extends ImmutablePureComponent {
|
|||
text
|
||||
backgroundColor='none'
|
||||
color='none'
|
||||
title='Remove'
|
||||
icon='caret-down'
|
||||
iconWidth='8px'
|
||||
iconHeight='8px'
|
||||
|
|
|
@ -25,6 +25,7 @@ import GlobeIcon from '../assets/globe_icon'
|
|||
import GroupIcon from '../assets/group_icon'
|
||||
import GroupAddIcon from '../assets/group_add_icon'
|
||||
import HappyIcon from '../assets/happy_icon'
|
||||
import HiddenIcon from '../assets/hidden_icon'
|
||||
import HomeIcon from '../assets/home_icon'
|
||||
import InvestorIcon from '../assets/investor_icon'
|
||||
import ItalicIcon from '../assets/italic_icon'
|
||||
|
@ -89,6 +90,7 @@ const ICONS = {
|
|||
'globe': GlobeIcon,
|
||||
'group': GroupIcon,
|
||||
'group-add': GroupAddIcon,
|
||||
'hidden': HiddenIcon,
|
||||
'happy': HappyIcon,
|
||||
'home': HomeIcon,
|
||||
'investor': InvestorIcon,
|
||||
|
@ -148,4 +150,5 @@ export default class Icon extends PureComponent {
|
|||
return <Asset {...options} />
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
import classNames from 'classnames/bind'
|
||||
|
||||
// : testing :
|
||||
// : todo :
|
||||
const placeholderSource = 'https://source.unsplash.com/random'
|
||||
const imageUnavailable = 'https://source.unsplash.com/random'
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
export default class Image extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
alt: PropTypes.string,
|
||||
alt: PropTypes.string.isRequired,
|
||||
src: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
fit: PropTypes.oneOf(['contain', 'cover', 'tile', 'none']),
|
||||
nullable: PropTypes.bool,
|
||||
lazy: PropTypes.bool,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -32,29 +29,41 @@ export default class Image extends PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { src, fit, className, nullable, ...otherProps } = this.props
|
||||
const {
|
||||
src,
|
||||
fit,
|
||||
className,
|
||||
nullable,
|
||||
lazy,
|
||||
...otherProps
|
||||
} = this.props
|
||||
const { error } = this.state
|
||||
|
||||
let source = src || placeholderSource
|
||||
const classes = cx(className, {
|
||||
default: 1,
|
||||
objectFitCover: fit === 'cover'
|
||||
objectFitCover: !!src && fit === 'cover',
|
||||
backgroundSubtle2: 1,
|
||||
})
|
||||
|
||||
//If error and not our own image
|
||||
if (error && nullable) {
|
||||
return null
|
||||
} else if (error) {
|
||||
source = imageUnavailable
|
||||
}
|
||||
|
||||
if (!src) {
|
||||
return (
|
||||
<div className={classes} />
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<img
|
||||
className={classes}
|
||||
{...otherProps}
|
||||
src={source}
|
||||
src={src}
|
||||
onError={this.handleOnError}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -22,7 +22,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||
|
||||
export default
|
||||
@connect(makeMapStateToProps, mapDispatchToProps)
|
||||
class IntersectionObserverArticle extends Component {
|
||||
class IntersectionObserverArticle extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
intersectionObserverWrapper: PropTypes.object.isRequired,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import moment from 'moment'
|
||||
import {
|
||||
FormattedMessage,
|
||||
defineMessages,
|
||||
|
@ -46,7 +45,7 @@ class LinkFooter extends PureComponent {
|
|||
render() {
|
||||
const { onOpenHotkeys, intl } = this.props
|
||||
|
||||
const currentYear = moment().format('YYYY')
|
||||
const currentYear = new Date().getFullYear()
|
||||
|
||||
const linkFooterItems = [
|
||||
{
|
||||
|
|
|
@ -7,7 +7,9 @@ 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 Button from '../button'
|
||||
import SensitiveMediaItem from '../../components/sensitive_media_item'
|
||||
import Text from '../text'
|
||||
|
||||
const messages = defineMessages({
|
||||
toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' },
|
||||
|
@ -16,6 +18,7 @@ const messages = defineMessages({
|
|||
});
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
class Item extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
|
@ -95,7 +98,7 @@ class Item extends ImmutablePureComponent {
|
|||
const hash = this.props.attachment.get('blurhash');
|
||||
const pixels = decode(hash, 32, 32);
|
||||
|
||||
if (pixels) {
|
||||
if (pixels && this.canvas) {
|
||||
const ctx = this.canvas.getContext('2d');
|
||||
const imageData = new ImageData(pixels, 32, 32);
|
||||
|
||||
|
@ -148,12 +151,12 @@ class Item extends ImmutablePureComponent {
|
|||
|
||||
if (attachment.get('type') === 'unknown') {
|
||||
return (
|
||||
<div className={[_s.default].join(' ')} key={attachment.get('id')} style={{ position, float, left, top, right, bottom, height, borderRadius, width: `${width}%` }}>
|
||||
<a className='media-gallery__item-thumbnail' href={attachment.get('remote_url')} target='_blank' style={{ cursor: 'pointer' }}>
|
||||
<canvas width={32} height={32} ref={this.setCanvasRef} className='media-gallery__preview' />
|
||||
<div className={[_s.default, _s.positionAbsolute].join(' ')} key={attachment.get('id')} style={{ position, float, left, top, right, bottom, height, borderRadius, width: `${width}%` }}>
|
||||
<a className={[_s.default, _s.heigh100PC, _s.width100PC, _s.cursorPointer].join(' ')} href={attachment.get('remote_url')} target='_blank' rel='noreferrer noopener'>
|
||||
<canvas width={32} height={32} ref={this.setCanvasRef} className={[_s.default, _s.heigh100PC, _s.width100PC].join(' ')} />
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
} else if (attachment.get('type') === 'image') {
|
||||
const previewUrl = attachment.get('preview_url');
|
||||
const previewWidth = attachment.getIn(['meta', 'small', 'width']);
|
||||
|
@ -213,14 +216,19 @@ class Item extends ImmutablePureComponent {
|
|||
playsInline
|
||||
/>
|
||||
|
||||
<span className='media-gallery__gifv__label'>GIF</span>
|
||||
<div className={[_s.default, _s.positionAbsolute, _s.z2, _s.radiusSmall, _s.backgroundColorOpaque, _s.px5, _s.py5, _s.mr10, _s.mb10, _s.bottom0, _s.right0].join(' ')}>
|
||||
<Text size='extraSmall' color='white' weight='medium'>GIF</Text>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={[_s.defeault, _s.positionAbsolute].join(' ')} key={attachment.get('id')} style={{ position, float, left, top, right, bottom, height, width: `${width}%` }}>
|
||||
<canvas width={0} height={0} ref={this.setCanvasRef} className={_s.displayNone} />
|
||||
{
|
||||
!visible && !this.state.loaded &&
|
||||
<canvas width={32} height={32} ref={this.setCanvasRef} className={[_s.default, _s.heigh100PC, _s.width100PC].join(' ')} />
|
||||
}
|
||||
{visible && thumbnail}
|
||||
</div>
|
||||
);
|
||||
|
@ -258,7 +266,9 @@ class MediaGallery extends PureComponent {
|
|||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!is(nextProps.media, this.props.media) && nextProps.visible === undefined) {
|
||||
this.setState({ visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all' });
|
||||
this.setState({
|
||||
visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all',
|
||||
})
|
||||
} else if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
|
||||
this.setState({ visible: nextProps.visible });
|
||||
}
|
||||
|
@ -294,14 +304,12 @@ class MediaGallery extends PureComponent {
|
|||
sensitive,
|
||||
height,
|
||||
defaultWidth,
|
||||
reduced
|
||||
reduced,
|
||||
} = this.props
|
||||
const { visible } = this.state
|
||||
|
||||
const width = this.state.width || defaultWidth;
|
||||
|
||||
let children, spoilerButton;
|
||||
|
||||
const style = {};
|
||||
const size = media.take(4).size;
|
||||
|
||||
|
@ -312,7 +320,7 @@ class MediaGallery extends PureComponent {
|
|||
const panoSize_px = `${Math.floor(width / maximumAspectRatio)}px`;
|
||||
let itemsDimensions = [];
|
||||
|
||||
if (size == 1 && width) {
|
||||
if (size === 1 && width && visible) {
|
||||
const aspectRatio = media.getIn([0, 'meta', 'small', 'aspect']);
|
||||
|
||||
if (isPanoramic(aspectRatio)) {
|
||||
|
@ -322,13 +330,13 @@ class MediaGallery extends PureComponent {
|
|||
} else {
|
||||
style.height = Math.floor(width / aspectRatio);
|
||||
}
|
||||
} else if (size > 1 && width) {
|
||||
} else if (size > 1 && width && visible) {
|
||||
const ar1 = media.getIn([0, 'meta', 'small', 'aspect']);
|
||||
const ar2 = media.getIn([1, 'meta', 'small', 'aspect']);
|
||||
const ar3 = media.getIn([2, 'meta', 'small', 'aspect']);
|
||||
const ar4 = media.getIn([3, 'meta', 'small', 'aspect']);
|
||||
|
||||
if (size == 2) {
|
||||
if (size === 2) {
|
||||
if (isPortrait(ar1) && isPortrait(ar2)) {
|
||||
style.height = width - (width / maximumAspectRatio);
|
||||
} else if (isPanoramic(ar1) && isPanoramic(ar2)) {
|
||||
|
@ -378,7 +386,7 @@ class MediaGallery extends PureComponent {
|
|||
{ w: 50, h: '100%', l: '2px', br: ['tr', 'br'] },
|
||||
];
|
||||
}
|
||||
} else if (size == 3) {
|
||||
} else if (size === 3) {
|
||||
if (isPanoramic(ar1) && isPanoramic(ar2) && isPanoramic(ar3)) {
|
||||
style.height = panoSize * 3;
|
||||
} else if (isPortrait(ar1) && isPortrait(ar2) && isPortrait(ar3)) {
|
||||
|
@ -391,7 +399,7 @@ class MediaGallery extends PureComponent {
|
|||
|
||||
if (isPanoramic(ar1) && isNonConformingRatio(ar2) && isNonConformingRatio(ar3)) {
|
||||
itemsDimensions = [
|
||||
{ w: 100, h: `50%`, b: '2px', br: ['tl', 'tr'] },
|
||||
{ w: 100, h: '50%', b: '2px', br: ['tl', 'tr'] },
|
||||
{ w: 50, h: '50%', t: '2px', r: '2px', br: ['bl'] },
|
||||
{ w: 50, h: '50%', t: '2px', l: '2px', br: ['br'] },
|
||||
];
|
||||
|
@ -403,7 +411,7 @@ class MediaGallery extends PureComponent {
|
|||
];
|
||||
} else if (isPortrait(ar1) && isNonConformingRatio(ar2) && isNonConformingRatio(ar3)) {
|
||||
itemsDimensions = [
|
||||
{ w: 50, h: `100%`, r: '2px', br: ['tl', 'bl'] },
|
||||
{ w: 50, h: '100%', r: '2px', br: ['tl', 'bl'] },
|
||||
{ w: 50, h: '50%', b: '2px', l: '2px', br: ['tr'] },
|
||||
{ w: 50, h: '50%', t: '2px', l: '2px', br: ['br'] },
|
||||
];
|
||||
|
@ -411,7 +419,7 @@ class MediaGallery extends PureComponent {
|
|||
itemsDimensions = [
|
||||
{ w: 50, h: '50%', b: '2px', r: '2px', br: ['tl'] },
|
||||
{ w: 50, h: '50%', l: '-2px', b: '-2px', pos: 'absolute', float: 'none', br: ['bl'] },
|
||||
{ w: 50, h: `100%`, r: '-2px', t: '0px', b: '0px', pos: 'absolute', float: 'none', br: ['tr', 'br'] },
|
||||
{ w: 50, h: '100%', r: '-2px', t: '0px', b: '0px', pos: 'absolute', float: 'none', br: ['tr', 'br'] },
|
||||
];
|
||||
} else if (
|
||||
(isNonConformingRatio(ar1) && isPortrait(ar2) && isNonConformingRatio(ar3)) ||
|
||||
|
@ -419,7 +427,7 @@ class MediaGallery extends PureComponent {
|
|||
) {
|
||||
itemsDimensions = [
|
||||
{ w: 50, h: '50%', b: '2px', r: '2px', br: ['tl'] },
|
||||
{ w: 50, h: `100%`, l: '2px', float: 'right', br: ['tr', 'br'] },
|
||||
{ w: 50, h: '100%', l: '2px', float: 'right', br: ['tr', 'br'] },
|
||||
{ w: 50, h: '50%', t: '2px', r: '2px', br: ['bl'] },
|
||||
];
|
||||
} else if (
|
||||
|
@ -444,10 +452,10 @@ class MediaGallery extends PureComponent {
|
|||
itemsDimensions = [
|
||||
{ w: 50, h: '50%', b: '2px', r: '2px', br: ['tl'] },
|
||||
{ w: 50, h: '50%', b: '2px', l: '2px', br: ['tr'] },
|
||||
{ w: 100, h: `50%`, t: '2px', br: ['bl', 'br'] },
|
||||
{ w: 100, h: '50%', t: '2px', br: ['bl', 'br'] },
|
||||
];
|
||||
}
|
||||
} else if (size == 4) {
|
||||
} else if (size === 4) {
|
||||
if (
|
||||
(isPortrait(ar1) && isPortrait(ar2) && isPortrait(ar3) && isPortrait(ar4)) ||
|
||||
(isPortrait(ar1) && isPortrait(ar2) && isPortrait(ar3) && isNonConformingRatio(ar4)) ||
|
||||
|
@ -491,7 +499,7 @@ class MediaGallery extends PureComponent {
|
|||
{ w: 67, h: '100%', r: '2px' },
|
||||
{ w: 33, h: '33%', b: '4px', l: '2px' },
|
||||
{ w: 33, h: '33%', l: '2px' },
|
||||
{ w: 33, h: '33%', t: '4px', l: '2px' }
|
||||
{ w: 33, h: '33%', t: '4px', l: '2px' },
|
||||
];
|
||||
} else {
|
||||
itemsDimensions = [
|
||||
|
@ -512,7 +520,11 @@ class MediaGallery extends PureComponent {
|
|||
style.height = width / 2
|
||||
}
|
||||
|
||||
children = media.take(4).map((attachment, i) => (
|
||||
if (!visible) {
|
||||
style.height = 'auto'
|
||||
}
|
||||
|
||||
const children = media.take(4).map((attachment, i) => (
|
||||
<Item
|
||||
key={attachment.get('id')}
|
||||
onClick={this.handleClick}
|
||||
|
@ -523,28 +535,16 @@ class MediaGallery extends PureComponent {
|
|||
visible={visible}
|
||||
dimensions={itemsDimensions[i]}
|
||||
/>
|
||||
));
|
||||
|
||||
if (visible) {
|
||||
spoilerButton = <Button title={intl.formatMessage(messages.toggle_visible)} icon='eye-slash' overlay onClick={this.handleOpen} />;
|
||||
} else {
|
||||
spoilerButton = (
|
||||
<button type='button' onClick={this.handleOpen} className='spoiler-button__overlay'>
|
||||
<span className='spoiler-button__overlay__label'>
|
||||
{intl.formatMessage(sensitive ? messages.warning : messages.hidden)}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
))
|
||||
|
||||
const containerClasses = cx({
|
||||
default: 1,
|
||||
displayBlock: 1,
|
||||
overflowHidden: 1,
|
||||
borderColorSecondary: size === 1,
|
||||
borderTop1PX: size === 1,
|
||||
borderBottom1PX: size === 1,
|
||||
px5: size > 1,
|
||||
borderColorSecondary: size === 1 && visible,
|
||||
borderTop1PX: size === 1 && visible,
|
||||
borderBottom1PX: size === 1 && visible,
|
||||
px5: size > 1 && visible,
|
||||
})
|
||||
|
||||
return (
|
||||
|
@ -554,14 +554,30 @@ class MediaGallery extends PureComponent {
|
|||
ref={this.handleRef}
|
||||
>
|
||||
|
||||
{ /* : todo :
|
||||
<div className={classNames('spoiler-button', { 'spoiler-button--minified': visible })}>
|
||||
{spoilerButton}
|
||||
</div> */ }
|
||||
{
|
||||
!visible && sensitive &&
|
||||
<SensitiveMediaItem onClick={this.handleOpen} />
|
||||
}
|
||||
|
||||
{
|
||||
visible &&
|
||||
<div className={[_s.default, _s.displayBlock, _s.width100PC, _s.height100PC, _s.overflowHidden].join(' ')}>
|
||||
{children}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
visible && sensitive &&
|
||||
<div className={[_s.positionAbsolute, _s.z2, _s.top0, _s.right0, _s.mt10, _s.mr10].join(' ')}>
|
||||
<Button
|
||||
title={intl.formatMessage(messages.toggle_visible)}
|
||||
icon='hidden'
|
||||
backgroundColor='none'
|
||||
className={[_s.px10, _s.backgroundColorBlackOpaque_onHover].join(' ')}
|
||||
onClick={this.handleOpen}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -208,11 +208,10 @@ class GifResultsCollection extends PureComponent {
|
|||
render() {
|
||||
const { results, handleSelectGifResult } = this.props
|
||||
|
||||
// : todo :
|
||||
const count = results.length
|
||||
const columnIndex = 10
|
||||
|
||||
console.log("results:", results)
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.height100PC, _s.flexRow, _s.width100PC].join(' ')}>
|
||||
<GifResultsCollectionColumn
|
||||
|
|
|
@ -48,8 +48,7 @@ class ModalBase extends PureComponent {
|
|||
activeElement = this.state.revealed ? document.activeElement : null
|
||||
|
||||
handleKeyUp = (e) => {
|
||||
if ((e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27)
|
||||
&& !!this.props.children) {
|
||||
if ((e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27) && !!this.props.children) {
|
||||
this.handleOnClose()
|
||||
}
|
||||
}
|
||||
|
@ -57,9 +56,9 @@ class ModalBase extends PureComponent {
|
|||
handleOnClose = (e) => {
|
||||
const { onOpenModal, composeText, composeId, onClose, intl, type, onCancelReplyCompose } = this.props
|
||||
|
||||
if (this.dialog !== e.target) return
|
||||
if (!!e && this.dialog !== e.target) return
|
||||
|
||||
if (!composeId && composeText && type == 'COMPOSE') {
|
||||
if (!composeId && composeText && type === 'COMPOSE') {
|
||||
onOpenModal('CONFIRM', {
|
||||
message: intl.formatMessage(messages.delete),
|
||||
confirm: intl.formatMessage(messages.confirm),
|
||||
|
|
|
@ -69,8 +69,8 @@ const MODAL_COMPONENTS = {
|
|||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
type: state.get('modal').modalType,
|
||||
props: state.get('modal').modalProps,
|
||||
type: state.getIn(['modal', 'modalType']),
|
||||
props: state.getIn(['modal', 'modalProps'], {}),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
|
|
|
@ -61,4 +61,5 @@ class ProUpgradeModal extends ImmutablePureComponent {
|
|||
</ModalLayout>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes'
|
|||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { Manager, Reference, Popper } from 'react-popper'
|
||||
import classnames from 'classnames/bind'
|
||||
import Overlay from 'react-overlays/lib/Overlay'
|
||||
import spring from 'react-motion/lib/spring'
|
||||
import Motion from '../../features/ui/util/optional_motion'
|
||||
import { openPopover, closePopover } from '../../actions/popover'
|
||||
|
@ -14,7 +13,7 @@ const cx = classnames.bind(_s)
|
|||
let id = 0
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
isModalOpen: state.get('modal').modalType === 'ACTIONS',
|
||||
isModalOpen: state.getIn(['modal', 'modalType']) === 'ACTIONS',
|
||||
popoverPlacement: state.getIn(['popover', 'placement']),
|
||||
openPopoverType: state.getIn(['popover', 'popoverType']),
|
||||
})
|
||||
|
@ -123,7 +122,7 @@ class PopoverBase extends ImmutablePureComponent {
|
|||
displayNone: !visible,
|
||||
})
|
||||
|
||||
console.log("targetRef:", targetRef)
|
||||
console.log('targetRef:', targetRef)
|
||||
|
||||
|
||||
return (
|
||||
|
|
|
@ -32,8 +32,8 @@ const POPOVER_COMPONENTS = {
|
|||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
type: state.get('popover').popoverType,
|
||||
props: state.get('popover').popoverProps,
|
||||
type: state.getIn(['popover', 'popoverType']),
|
||||
props: state.getIn(['popover', 'popoverProps'], {}),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
|
@ -45,6 +45,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||
export default
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
class PopoverRoot extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
type: PropTypes.string,
|
||||
props: PropTypes.object,
|
||||
|
@ -172,4 +173,5 @@ class PopoverRoot extends PureComponent {
|
|||
</PopoverBase>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -42,7 +42,7 @@ const mapStateToProps = state => {
|
|||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
|
||||
openProfileOptionsPopover(props) {
|
||||
console.log("props:", props)
|
||||
console.log('props:', props)
|
||||
dispatch(openPopover('PROFILE_OPTIONS', props))
|
||||
},
|
||||
|
||||
|
@ -112,9 +112,9 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||
|
||||
// : todo :
|
||||
makeInfo() {
|
||||
const { account, intl } = this.props;
|
||||
const { account, intl } = this.props
|
||||
|
||||
let info = [];
|
||||
const info = []
|
||||
|
||||
if (!account || !me) return info;
|
||||
|
||||
|
@ -130,8 +130,8 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||
info.push(<span key='domain_blocked' className='relationship-tag'>{intl.formatMessage(messages.domainBlocked)}</span>);
|
||||
}
|
||||
|
||||
return info;
|
||||
};
|
||||
return info
|
||||
}
|
||||
|
||||
setOpenMoreNodeRef = (n) => {
|
||||
this.openMoreNode = n
|
||||
|
@ -175,11 +175,10 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||
let buttonOptions = {}
|
||||
|
||||
if (!account) {
|
||||
console.log("no account")
|
||||
}
|
||||
else {
|
||||
console.log('no account')
|
||||
} else {
|
||||
if (!account.get('relationship')) {
|
||||
console.log("no relationship")
|
||||
console.log('no relationship')
|
||||
// Wait until the relationship is loaded
|
||||
} else if (account.getIn(['relationship', 'requested'])) {
|
||||
buttonText = intl.formatMessage(messages.requested)
|
||||
|
@ -209,7 +208,7 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||
backgroundColor: 'tertiary',
|
||||
}
|
||||
} else {
|
||||
console.log("no nothin")
|
||||
console.log('no nothin')
|
||||
}
|
||||
|
||||
// if (account.get('id') !== me && account.get('relationship', null) !== null) {
|
||||
|
@ -240,8 +239,8 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||
// }
|
||||
}
|
||||
|
||||
console.log("buttonOptions:", buttonText, buttonOptions)
|
||||
console.log("account: ", account)
|
||||
console.log('buttonOptions:', buttonText, buttonOptions)
|
||||
console.log('account: ', account)
|
||||
|
||||
|
||||
// : todo : "follows you", "mutual follow"
|
||||
|
@ -253,6 +252,7 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||
!headerMissing &&
|
||||
<div className={[_s.default, _s.height350PX, _s.width100PC, _s.radiusSmall, _s.overflowHidden].join(' ')}>
|
||||
<Image
|
||||
alt='Cover Photo'
|
||||
className={_s.height350PX}
|
||||
src={headerSrc}
|
||||
/>
|
||||
|
|
|
@ -30,7 +30,7 @@ const makeMapStateToProps = () => {
|
|||
const ids = [status.get('id')]
|
||||
|
||||
while (ids.length > 0) {
|
||||
let id = ids.shift();
|
||||
const id = ids.shift();
|
||||
const replies = state.getIn(['contexts', 'replies', id])
|
||||
|
||||
if (status.get('id') !== id) {
|
||||
|
|
|
@ -66,52 +66,44 @@ const getUnitDelay = units => {
|
|||
export const timeAgoString = (intl, date, now, year) => {
|
||||
const delta = now - date.getTime()
|
||||
|
||||
let relativeTime
|
||||
|
||||
if (delta < 10 * SECOND) {
|
||||
relativeTime = intl.formatMessage(messages.just_now)
|
||||
return intl.formatMessage(messages.just_now)
|
||||
} else if (delta < 7 * DAY) {
|
||||
if (delta < MINUTE) {
|
||||
relativeTime = intl.formatMessage(messages.seconds, { number: Math.floor(delta / SECOND) })
|
||||
return intl.formatMessage(messages.seconds, { number: Math.floor(delta / SECOND) })
|
||||
} else if (delta < HOUR) {
|
||||
relativeTime = intl.formatMessage(messages.minutes, { number: Math.floor(delta / MINUTE) })
|
||||
return intl.formatMessage(messages.minutes, { number: Math.floor(delta / MINUTE) })
|
||||
} else if (delta < DAY) {
|
||||
relativeTime = intl.formatMessage(messages.hours, { number: Math.floor(delta / HOUR) })
|
||||
return intl.formatMessage(messages.hours, { number: Math.floor(delta / HOUR) })
|
||||
} else {
|
||||
relativeTime = intl.formatMessage(messages.days, { number: Math.floor(delta / DAY) })
|
||||
return intl.formatMessage(messages.days, { number: Math.floor(delta / DAY) })
|
||||
}
|
||||
} else if (date.getFullYear() === year) {
|
||||
relativeTime = intl.formatDate(date, shortDateFormatOptions)
|
||||
} else {
|
||||
relativeTime = intl.formatDate(date, { ...shortDateFormatOptions, year: 'numeric' })
|
||||
return intl.formatDate(date, shortDateFormatOptions)
|
||||
}
|
||||
|
||||
return relativeTime
|
||||
return intl.formatDate(date, { ...shortDateFormatOptions, year: 'numeric' })
|
||||
}
|
||||
|
||||
const timeRemainingString = (intl, date, now) => {
|
||||
const delta = date.getTime() - now
|
||||
|
||||
let relativeTime
|
||||
|
||||
if (delta < 10 * SECOND) {
|
||||
relativeTime = intl.formatMessage(messages.moments_remaining)
|
||||
return intl.formatMessage(messages.moments_remaining)
|
||||
} else if (delta < MINUTE) {
|
||||
relativeTime = intl.formatMessage(messages.seconds_remaining, { number: Math.floor(delta / SECOND) })
|
||||
return intl.formatMessage(messages.seconds_remaining, { number: Math.floor(delta / SECOND) })
|
||||
} else if (delta < HOUR) {
|
||||
relativeTime = intl.formatMessage(messages.minutes_remaining, { number: Math.floor(delta / MINUTE) })
|
||||
return intl.formatMessage(messages.minutes_remaining, { number: Math.floor(delta / MINUTE) })
|
||||
} else if (delta < DAY) {
|
||||
relativeTime = intl.formatMessage(messages.hours_remaining, { number: Math.floor(delta / HOUR) })
|
||||
} else {
|
||||
relativeTime = intl.formatMessage(messages.days_remaining, { number: Math.floor(delta / DAY) })
|
||||
return intl.formatMessage(messages.hours_remaining, { number: Math.floor(delta / HOUR) })
|
||||
}
|
||||
|
||||
return relativeTime
|
||||
return intl.formatMessage(messages.days_remaining, { number: Math.floor(delta / DAY) })
|
||||
}
|
||||
|
||||
export default
|
||||
@injectIntl
|
||||
class RelativeTimestamp extends Component {
|
||||
class RelativeTimestamp extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { throttle } from 'lodash'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { List as ImmutableList } from 'immutable'
|
||||
import IntersectionObserverArticle from './intersection_observer_article'
|
||||
import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper'
|
||||
|
@ -199,7 +199,15 @@ export default class ScrollableList extends PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { children, scrollKey, showLoading, isLoading, hasMore, emptyMessage, onLoadMore } = this.props;
|
||||
const {
|
||||
children,
|
||||
scrollKey,
|
||||
showLoading,
|
||||
isLoading,
|
||||
hasMore,
|
||||
emptyMessage,
|
||||
onLoadMore,
|
||||
} = this.props
|
||||
const childrenCount = React.Children.count(children);
|
||||
|
||||
const trackScroll = true; //placeholder
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import { injectIntl, defineMessages } from 'react-intl'
|
||||
import Button from './button'
|
||||
import Text from './text'
|
||||
|
||||
const messages = defineMessages({
|
||||
warning: { id: 'status.sensitive_warning_2', defaultMessage: 'The following media includes potentially sensitive content.' },
|
||||
view: { id: 'view', defaultMessage: 'View' },
|
||||
});
|
||||
|
||||
export default
|
||||
@injectIntl
|
||||
class SensitiveMediaItem extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
intl,
|
||||
onClick,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.px15, _s.pt5].join(' ')}>
|
||||
<div className={[_s.default, _s.flexRow, _s.radiusSmall, _s.backgroundColorSecondary3, _s.py10, _s.px15, _s.height100PC, _s.width100PC].join(' ')}>
|
||||
<div className={[_s.default, _s.justifyContentCenter, _s.flexNormal].join(' ')}>
|
||||
<Text color='secondary'>
|
||||
{intl.formatMessage(messages.warning)}
|
||||
</Text>
|
||||
</div>
|
||||
<div className={[_s.default, _s.justifyContentCenter, _s.marginLeftAuto].join(' ')}>
|
||||
<Button
|
||||
onClick={onClick}
|
||||
color='tertiary'
|
||||
backgroundColor='none'
|
||||
className={_s.backgroundSubtle2Dark_onHover}
|
||||
>
|
||||
<Text color='inherit' weight='bold' size='medium'>
|
||||
{intl.formatMessage(messages.view)}
|
||||
</Text>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -22,7 +22,7 @@ const messages = defineMessages({
|
|||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
||||
filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },
|
||||
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
|
||||
lists: { id: 'column.lists', defaultMessage: 'Lists', },
|
||||
lists: { id: 'column.lists', defaultMessage: 'Lists' },
|
||||
apps: { id: 'tabs_bar.apps', defaultMessage: 'Apps' },
|
||||
more: { id: 'sidebar.more', defaultMessage: 'More' },
|
||||
pro: { id: 'promo.gab_pro', defaultMessage: 'Upgrade to GabPRO' },
|
||||
|
@ -37,7 +37,7 @@ const mapStateToProps = state => {
|
|||
|
||||
return {
|
||||
account: getAccount(state, me),
|
||||
moreOpen: state.get('popover').popoverType === 'SIDEBAR_MORE',
|
||||
moreOpen: state.getIn(['popover', 'popoverType']) === 'SIDEBAR_MORE',
|
||||
notificationCount: state.getIn(['notifications', 'unread']),
|
||||
homeItemsQueueCount: state.getIn(['timelines', 'home', 'totalQueuedItemsCount']),
|
||||
showCommunityTimeline: state.getIn(['settings', 'community', 'shows', 'inSidebar']),
|
||||
|
@ -95,7 +95,7 @@ class Sidebar extends ImmutablePureComponent {
|
|||
notificationCount,
|
||||
homeItemsQueueCount,
|
||||
showCommunityTimeline,
|
||||
moreOpen
|
||||
moreOpen,
|
||||
} = this.props
|
||||
|
||||
// : todo :
|
||||
|
@ -104,7 +104,7 @@ class Sidebar extends ImmutablePureComponent {
|
|||
const acct = account.get('acct')
|
||||
const isPro = account.get('is_pro')
|
||||
|
||||
console.log("showCommunityTimeline:", showCommunityTimeline)
|
||||
console.log('showCommunityTimeline:', showCommunityTimeline)
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import classNames from 'classnames/bind'
|
||||
import Button from './button'
|
||||
import Icon from './icon'
|
||||
import Image from './image'
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
export default class SidebarSectionItem extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
}
|
||||
|
@ -45,7 +47,7 @@ export default class SidebarSectionItem extends PureComponent {
|
|||
count,
|
||||
onClick,
|
||||
href,
|
||||
buttonRef
|
||||
buttonRef,
|
||||
} = this.props
|
||||
const { hovering } = this.state
|
||||
|
||||
|
@ -65,6 +67,7 @@ export default class SidebarSectionItem extends PureComponent {
|
|||
radiusSmall: 1,
|
||||
mt2: 1,
|
||||
border1PX: 1,
|
||||
outlineNone: 1,
|
||||
borderColorTransparent: !shouldShowActive,
|
||||
borderColorSecondary: shouldShowActive,
|
||||
backgroundTransparent: !shouldShowActive,
|
||||
|
@ -77,7 +80,6 @@ export default class SidebarSectionItem extends PureComponent {
|
|||
fontSize15PX: 1,
|
||||
text: 1,
|
||||
textOverflowEllipsis: 1,
|
||||
outlineNone: 1,
|
||||
colorSecondary: !hovering && !active && !me && !shouldShowActive,
|
||||
colorPrimary: shouldShowActive || me,
|
||||
})
|
||||
|
@ -111,14 +113,15 @@ export default class SidebarSectionItem extends PureComponent {
|
|||
buttonRef={buttonRef}
|
||||
onMouseEnter={() => this.handleOnMouseEnter()}
|
||||
onMouseLeave={() => this.handleOnMouseLeave()}
|
||||
className={[_s.default, _s.noUnderline, _s.cursorPointer, _s.width100PC, _s.backgroundTransparent].join(' ')}
|
||||
className={[_s.default, _s.noUnderline, _s.outlineNone, _s.cursorPointer, _s.width100PC, _s.backgroundTransparent].join(' ')}
|
||||
>
|
||||
<div className={containerClasses}>
|
||||
<div className={[_s.default]}>
|
||||
{ icon && <Icon id={icon} className={iconClasses} width={iconSize} height={iconSize} /> }
|
||||
{ image &&
|
||||
<img
|
||||
className={[_s.default, _s.circle].join(' ')}
|
||||
<Image
|
||||
alt={title}
|
||||
className={_s.circle}
|
||||
width={iconSize}
|
||||
height={iconSize}
|
||||
src={image}
|
||||
|
@ -137,4 +140,5 @@ export default class SidebarSectionItem extends PureComponent {
|
|||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -272,7 +272,7 @@ class Status extends ImmutablePureComponent {
|
|||
group,
|
||||
promoted,
|
||||
borderless,
|
||||
isChild
|
||||
isChild,
|
||||
} = this.props
|
||||
|
||||
let media = null
|
||||
|
@ -287,7 +287,7 @@ class Status extends ImmutablePureComponent {
|
|||
// status = status.get('reblog');
|
||||
// }
|
||||
|
||||
let { status, ...other } = this.props;
|
||||
const { status, ...other } = this.props;
|
||||
|
||||
// console.log("replies:", this.props.replies)
|
||||
|
||||
|
|
|
@ -169,11 +169,12 @@ export default class Card extends ImmutablePureComponent {
|
|||
</div>
|
||||
)
|
||||
|
||||
// : todo : use <Image />
|
||||
let embed = ''
|
||||
let thumbnail = interactive ?
|
||||
<img src={cardImg} className={[_s.default, _s.objectFitCover, _s.positionAbsolute, _s.width100PC, _s.height100PC, _s.top0, _s.right0, _s.bottom0, _s.left0].join(' ')} />
|
||||
const thumbnail = interactive ?
|
||||
<img alt={''} src={cardImg} className={[_s.default, _s.objectFitCover, _s.positionAbsolute, _s.width100PC, _s.height100PC, _s.top0, _s.right0, _s.bottom0, _s.left0].join(' ')} />
|
||||
:
|
||||
<img src={cardImg} className={[_s.default, _s.objectFitCover, _s.width330PX, _s.height220PX].join(' ')} />
|
||||
<img alt={''} src={cardImg} className={[_s.default, _s.objectFitCover, _s.width330PX, _s.height220PX].join(' ')} />
|
||||
|
||||
if (interactive) {
|
||||
if (embedded) {
|
||||
|
|
|
@ -224,12 +224,17 @@ class StatusContent extends ImmutablePureComponent {
|
|||
displayNone: hidden,
|
||||
})
|
||||
|
||||
const containerClasses = cx({
|
||||
statusContent: 1,
|
||||
px15: !isComment,
|
||||
})
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[].join(' ')}
|
||||
ref={this.setRef}
|
||||
tabIndex='0'
|
||||
className={[_s.px15, _s.statusContent].join(' ')}
|
||||
className={containerClasses}
|
||||
style={directionStyle}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
onMouseUp={this.handleMouseUp}
|
||||
|
@ -317,11 +322,18 @@ class StatusContent extends ImmutablePureComponent {
|
|||
)
|
||||
}
|
||||
|
||||
const containerClasses = cx({
|
||||
statusContent: 1,
|
||||
px15: !isComment,
|
||||
mb15: !isComment,
|
||||
mt5: isComment,
|
||||
})
|
||||
|
||||
return (
|
||||
<div
|
||||
tabIndex='0'
|
||||
ref={this.setRef}
|
||||
className={[_s.px15, _s.mb15, _s.statusContent].join(' ')}
|
||||
className={containerClasses}
|
||||
style={directionStyle}
|
||||
dangerouslySetInnerHTML={content}
|
||||
lang={status.get('language')}
|
||||
|
|
|
@ -10,7 +10,7 @@ export default class TimelineQueueButtonHeader extends PureComponent {
|
|||
onClick: PropTypes.func.isRequired,
|
||||
count: PropTypes.number,
|
||||
itemType: PropTypes.string,
|
||||
floating: PropTypes.bool
|
||||
floating: PropTypes.bool,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
|
|
|
@ -49,7 +49,7 @@ export default class TrendingItem extends PureComponent {
|
|||
author,
|
||||
publishDate,
|
||||
isLast,
|
||||
wide
|
||||
wide,
|
||||
} = this.props
|
||||
const { hovering } = this.state
|
||||
|
||||
|
@ -70,13 +70,14 @@ export default class TrendingItem extends PureComponent {
|
|||
})
|
||||
|
||||
const correctedAuthor = author.replace('www.', '')
|
||||
const correctedDescription = description.length > 120 ? `${description.substring(0, 120).trim()}...` : description
|
||||
const correctedDescription = description.length >= 120 ? `${description.substring(0, 120).trim()}...` : description
|
||||
|
||||
const image = (
|
||||
<Image
|
||||
nullable
|
||||
width='116px'
|
||||
height='78px'
|
||||
alt={title}
|
||||
src={imageUrl}
|
||||
className={[_s.radiusSmall, _s.overflowHidden, _s.mb10].join(' ')}
|
||||
/>
|
||||
|
@ -87,6 +88,7 @@ export default class TrendingItem extends PureComponent {
|
|||
noClasses
|
||||
href={url}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className={containerClasses}
|
||||
onMouseEnter={() => this.handleOnMouseEnter()}
|
||||
onMouseLeave={() => this.handleOnMouseLeave()}
|
||||
|
@ -104,7 +106,7 @@ export default class TrendingItem extends PureComponent {
|
|||
|
||||
{
|
||||
!!correctedDescription &&
|
||||
<div className={[_s.default, _s.heightMax60PX, _s.overflowHidden, _s.py5].join(' ')}>
|
||||
<div className={[_s.default, _s.heightMax56PX, _s.overflowHidden, _s.pt5, _s.mb5].join(' ')}>
|
||||
<Text size='small' color='secondary'>
|
||||
{correctedDescription}
|
||||
</Text>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import { is } from 'immutable'
|
||||
import { throttle } from 'lodash'
|
||||
import throttle from 'lodash.throttle'
|
||||
import classNames from 'classnames/bind'
|
||||
import { decode } from 'blurhash'
|
||||
import { isFullscreen, requestFullscreen, exitFullscreen } from '../utils/fullscreen'
|
||||
|
|
|
@ -28,7 +28,7 @@ import { boostModal, deleteModal } from '../initial_state';
|
|||
// import { showAlertForError } from '../actions/alerts';
|
||||
import {
|
||||
createRemovedAccount,
|
||||
groupRemoveStatus
|
||||
groupRemoveStatus,
|
||||
} from '../actions/groups';
|
||||
import { makeGetStatus } from '../selectors';
|
||||
import Status from '../components/status';
|
||||
|
@ -58,7 +58,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
|
||||
onReply (status, router) {
|
||||
dispatch((_, getState) => {
|
||||
let state = getState();
|
||||
const state = getState();
|
||||
if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: intl.formatMessage(messages.replyMessage),
|
||||
|
@ -73,7 +73,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
|
||||
onQuote (status, router) {
|
||||
dispatch((_, getState) => {
|
||||
let state = getState();
|
||||
const state = getState();
|
||||
if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: intl.formatMessage(messages.quoteMessage),
|
||||
|
@ -107,12 +107,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
},
|
||||
|
||||
onFavorite (status) {
|
||||
console.log("onFavorite...", status)
|
||||
console.log('onFavorite...', status)
|
||||
if (status.get('favourited')) {
|
||||
console.log("unfav...")
|
||||
console.log('unfav...')
|
||||
dispatch(unfavorite(status));
|
||||
} else {
|
||||
console.log("fav...")
|
||||
console.log('fav...')
|
||||
dispatch(favorite(status));
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import { createSelector } from 'reselect';
|
||||
import { debounce, sample } from 'lodash';
|
||||
import { sample } from 'lodash';
|
||||
import debounce from 'lodash.debounce'
|
||||
import { dequeueTimeline } from '../actions/timelines';
|
||||
import { scrollTopTimeline } from '../actions/timelines';
|
||||
import { fetchStatus } from '../actions/statuses';
|
||||
|
|
|
@ -84,7 +84,7 @@ class AccountGallery extends ImmutablePureComponent {
|
|||
isLoading,
|
||||
hasMore,
|
||||
intl,
|
||||
account
|
||||
account,
|
||||
} = this.props
|
||||
|
||||
if (!account) return null
|
||||
|
@ -109,7 +109,7 @@ class AccountGallery extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
{ /*
|
||||
attachments.size == 0 &&
|
||||
attachments.size === 0 &&
|
||||
<ColumnIndicator type='empty' message={intl.formatMessage(messages.none)} />
|
||||
*/ }
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { debounce } from 'lodash'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { fetchBlocks, expandBlocks } from '../actions/blocks'
|
||||
import AccountContainer from '../containers/account_container'
|
||||
import ColumnIndicator from '../components/column_indicator'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { debounce } from 'lodash'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { unblockDomain, fetchDomainBlocks, expandDomainBlocks } from '../actions/domain_blocks'
|
||||
import ColumnIndicator from '../components/column_indicator'
|
||||
import List from '../components/list'
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { length } from 'stringz'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import classNames from 'classnames/bind'
|
||||
import { length } from 'stringz'
|
||||
import CharacterCounter from '../../../../components/character_counter'
|
||||
import UploadForm from '../upload_form'
|
||||
import AutosuggestTextbox from '../../../../components/autosuggest_textbox'
|
||||
|
@ -15,7 +15,7 @@ import StatusVisibilityButton from '../../components/status_visibility_button'
|
|||
import EmojiPickerButton from '../../components/emoji_picker_button'
|
||||
import PollFormContainer from '../../containers/poll_form_container'
|
||||
import SchedulePostButton from '../schedule_post_button'
|
||||
import QuotedStatusPreviewContainer from '../../containers/quoted_status_preview_container'
|
||||
import StatusContainer from '../../../../containers/status_container'
|
||||
import Button from '../../../../components/button'
|
||||
import Avatar from '../../../../components/avatar'
|
||||
import { isMobile } from '../../../../utils/is_mobile'
|
||||
|
@ -29,7 +29,7 @@ const messages = defineMessages({
|
|||
spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' },
|
||||
publish: { id: 'compose_form.publish', defaultMessage: 'Gab' },
|
||||
publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}' },
|
||||
schedulePost: { id: 'compose_form.schedule_post', defaultMessage: 'Schedule Post' }
|
||||
schedulePost: { id: 'compose_form.schedule_post', defaultMessage: 'Schedule Post' },
|
||||
});
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
@ -79,6 +79,7 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
scheduledAt: PropTypes.instanceOf(Date),
|
||||
setScheduledAt: PropTypes.func.isRequired,
|
||||
replyToId: PropTypes.string,
|
||||
hasPoll: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -104,7 +105,7 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
handleClick = (e) => {
|
||||
if (!this.form) return false;
|
||||
if (e.target) {
|
||||
if (e.target.classList.contains('react-datepicker__time-list-item')) return;
|
||||
if (e.target.classList.contains('react-datepicker__time-list-item')) return false
|
||||
}
|
||||
if (!this.form.contains(e.target)) {
|
||||
this.handleClickOutside();
|
||||
|
@ -162,11 +163,11 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener("click", this.handleClick, false);
|
||||
document.addEventListener('click', this.handleClick, false);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener("click", this.handleClick, false);
|
||||
document.removeEventListener('click', this.handleClick, false);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
|
@ -201,19 +202,19 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
setForm = (c) => {
|
||||
this.form = c;
|
||||
this.form = c
|
||||
}
|
||||
|
||||
setSpoilerText = (c) => {
|
||||
this.spoilerText = c;
|
||||
this.spoilerText = c
|
||||
}
|
||||
|
||||
handleEmojiPick = (data) => {
|
||||
const { text } = this.props;
|
||||
const position = this.autosuggestTextarea.textbox.selectionStart;
|
||||
const needsSpace = data.custom && position > 0 && !allowedAroundShortCode.includes(text[position - 1]);
|
||||
const { text } = this.props
|
||||
const position = this.autosuggestTextarea.textbox.selectionStart
|
||||
const needsSpace = data.custom && position > 0 && !allowedAroundShortCode.includes(text[position - 1])
|
||||
|
||||
this.props.onPickEmoji(position, data, needsSpace);
|
||||
this.props.onPickEmoji(position, data, needsSpace)
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -230,11 +231,13 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
edit,
|
||||
scheduledAt,
|
||||
spoiler,
|
||||
replyToId
|
||||
replyToId,
|
||||
hasPoll,
|
||||
isUploading,
|
||||
} = this.props
|
||||
const disabled = this.props.isSubmitting;
|
||||
const text = [this.props.spoilerText, countableText(this.props.text)].join('');
|
||||
const disabledButton = disabled || this.props.isUploading || this.props.isChangingUpload || length(text) > maxPostCharacterCount || (text.length !== 0 && text.trim().length === 0 && !anyMedia);
|
||||
const disabledButton = disabled || isUploading || this.props.isChangingUpload || length(text) > maxPostCharacterCount || (text.length !== 0 && text.trim().length === 0 && !anyMedia);
|
||||
const shouldAutoFocus = autoFocus && !showSearch && !isMobile(window.innerWidth)
|
||||
|
||||
const parentContainerClasses = cx({
|
||||
|
@ -255,7 +258,8 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
const actionsContainerClasses = cx({
|
||||
default: 1,
|
||||
flexRow: 1,
|
||||
alignItemsCenter: 1,
|
||||
alignItemsCenter: !shouldCondense,
|
||||
alignItemsStart: shouldCondense,
|
||||
mt10: !shouldCondense,
|
||||
px15: !shouldCondense,
|
||||
})
|
||||
|
@ -313,19 +317,25 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
autoFocus={shouldAutoFocus}
|
||||
small={shouldCondense}
|
||||
textarea
|
||||
>
|
||||
/>
|
||||
|
||||
{
|
||||
(isUploading || anyMedia) &&
|
||||
<div className={[_s.default, _s.px15].join(' ')}>
|
||||
<UploadForm replyToId={replyToId} />
|
||||
{
|
||||
!edit &&
|
||||
<PollFormContainer replyToId={replyToId} />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
</AutosuggestTextbox>
|
||||
{
|
||||
!edit && hasPoll &&
|
||||
<div className={[_s.default, _s.px15].join(' ')}>
|
||||
<PollFormContainer replyToId={replyToId} />
|
||||
</div>
|
||||
}
|
||||
|
||||
{ /* quoteOfId && <QuotedStatusPreviewContainer id={quoteOfId} /> */}
|
||||
{
|
||||
/* : todo : quoteOfId && <StatusContainer id={quoteOfId} /> */
|
||||
}
|
||||
|
||||
<div className={actionsContainerClasses}>
|
||||
<div className={[_s.default, _s.flexRow, _s.marginRightAuto].join(' ')}>
|
||||
|
@ -359,7 +369,7 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
<CharacterCounter max={maxPostCharacterCount} text={text} />
|
||||
}
|
||||
|
||||
{
|
||||
{ /* : todo : show send on shouldCondense if any text */
|
||||
!shouldCondense &&
|
||||
<Button
|
||||
className={[_s.fontSize15PX, _s.px15].join(' ')}
|
||||
|
|
|
@ -7,7 +7,7 @@ const messages = defineMessages({
|
|||
})
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
active: state.get('popover').popoverType === 'EMOJI_PICKER',
|
||||
active: state.getIn(['popover', 'popoverType']) === 'EMOJI_PICKER',
|
||||
})
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
|
|
@ -9,7 +9,7 @@ const messages = defineMessages({
|
|||
})
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
active: !!state.getIn(['compose', 'gif']) || state.get('modal').modalType === 'GIF_PICKER',
|
||||
active: !!state.getIn(['compose', 'gif']) || state.getIn(['modal', 'modalType']) === 'GIF_PICKER',
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import DisplayName from '../../../components/display_name';
|
||||
import StatusContent from '../../../components/status_content';
|
||||
|
||||
// : todo : do we need this? make work inside of status/status content
|
||||
|
||||
export default class QuotedStatusPreview extends PureComponent {
|
||||
static propTypes = {
|
||||
status: ImmutablePropTypes.map,
|
||||
account: ImmutablePropTypes.map,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { status, account } = this.props;
|
||||
|
||||
return (
|
||||
<div className='compose-form__quote-preview'>
|
||||
<DisplayName account={account} />
|
||||
<StatusContent status={status} expanded={false} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -28,6 +28,11 @@ class StatusVisibilityButton extends PureComponent {
|
|||
intl: PropTypes.object.isRequired,
|
||||
small: PropTypes.bool,
|
||||
onOpenPopover: PropTypes.func.isRequired,
|
||||
value: PropTypes.oneOf([
|
||||
'private',
|
||||
'unlisted',
|
||||
'public',
|
||||
]),
|
||||
}
|
||||
|
||||
handleOnClick = () => {
|
||||
|
@ -42,7 +47,7 @@ class StatusVisibilityButton extends PureComponent {
|
|||
const {
|
||||
intl,
|
||||
small,
|
||||
value
|
||||
value,
|
||||
} = this.props
|
||||
|
||||
let icon;
|
||||
|
|
|
@ -24,7 +24,7 @@ class UploadForm extends ImmutablePureComponent {
|
|||
const {
|
||||
mediaIds,
|
||||
isUploading,
|
||||
uploadProgress
|
||||
uploadProgress,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
|
|
|
@ -71,7 +71,7 @@ class Compose extends ImmutablePureComponent {
|
|||
render () {
|
||||
const { showSearch, isSearchPage, intl } = this.props;
|
||||
|
||||
let header = '';
|
||||
const header = '';
|
||||
|
||||
return (
|
||||
<div className='drawer' role='region' aria-label={intl.formatMessage(messages.compose)}>
|
||||
|
|
|
@ -35,10 +35,11 @@ const mapStateToProps = (state, { replyToId }) => {
|
|||
isUploading: !isMatch ? false : state.getIn(['compose', 'is_uploading']),
|
||||
showSearch: !isMatch ? false : state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
|
||||
anyMedia: !isMatch ? false : state.getIn(['compose', 'media_attachments']).size > 0,
|
||||
isModalOpen: !isMatch ? false : state.get('modal').modalType === 'COMPOSE',
|
||||
isModalOpen: !isMatch ? false : state.getIn(['modal', 'modalType']) === 'COMPOSE',
|
||||
quoteOfId: !isMatch ? null : state.getIn(['compose', 'quote_of_id']),
|
||||
scheduledAt: !isMatch ? null : state.getIn(['compose', 'scheduled_at']),
|
||||
account: state.getIn(['accounts', me]),
|
||||
hasPoll: !isMatch ? false : state.getIn(['compose', 'poll']),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +85,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||
function mergeProps(stateProps, dispatchProps, ownProps) {
|
||||
return Object.assign({}, ownProps, {
|
||||
...stateProps,
|
||||
...dispatchProps
|
||||
...dispatchProps,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
import QuotedStatusPreview from '../components/quoted_status_preview';
|
||||
|
||||
const mapStateToProps = (state, { id }) => ({
|
||||
status: state.getIn(['statuses', id]),
|
||||
account: state.getIn(['accounts', state.getIn(['statuses', id, 'account'])]),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(QuotedStatusPreview);
|
|
@ -1,9 +1,9 @@
|
|||
import { urlRegex } from './url_regex';
|
||||
import { urlRegex } from './url_regex'
|
||||
|
||||
const urlPlaceholder = 'xxxxxxxxxxxxxxxxxxxxxxx';
|
||||
const urlPlaceholder = 'xxxxxxxxxxxxxxxxxxxxxxx'
|
||||
|
||||
export function countableText(inputText) {
|
||||
return inputText
|
||||
.replace(urlRegex, urlPlaceholder)
|
||||
.replace(/(^|[^\/\w])@(([a-z0-9_]+)@[a-z0-9\.\-]+[a-z0-9]+)/ig, '$1@$3');
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { debounce } from 'lodash';
|
||||
import debounce from 'lodash.debounce'
|
||||
import { fetchFollowRequests, expandFollowRequests } from '../../actions/accounts';
|
||||
import ColumnIndicator from '../../components/column_indicator';
|
||||
import AccountAuthorize from './components/account_authorize';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { debounce } from 'lodash'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import {
|
||||
fetchFollowers,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { debounce } from 'lodash'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import {
|
||||
fetchFollowing,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { debounce } from 'lodash';
|
||||
import debounce from 'lodash.debounce'
|
||||
import {
|
||||
fetchMembers,
|
||||
expandMembers,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { debounce } from 'lodash';
|
||||
import debounce from 'lodash.debounce'
|
||||
import ColumnIndicator from '../components/column_indicator';
|
||||
import {
|
||||
fetchRemovedAccounts,
|
||||
|
|
|
@ -12,6 +12,7 @@ const mapStateToProps = (state, { activeTab }) => ({
|
|||
export default
|
||||
@connect(mapStateToProps)
|
||||
class GroupsCollection extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
activeTab: PropTypes.string.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
|
@ -35,14 +36,32 @@ class GroupsCollection extends ImmutablePureComponent {
|
|||
return <ColumnIndicator type='loading' />
|
||||
}
|
||||
|
||||
const halfCount = parseInt(groupIds.size / 2)
|
||||
|
||||
console.log("halfCount", halfCount)
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.flexRow, _s.flexWrap].join(' ')}>
|
||||
<div className={[_s.default, _s.flexNormal].join(' ')}>
|
||||
<ScrollableList scrollKey='group-collection-column-1'>
|
||||
{
|
||||
groupIds.map((groupId, i) => (
|
||||
groupIds.slice(0, halfCount).map((groupId, i) => (
|
||||
<GroupCollectionItem key={`group-collection-item-${i}`} id={groupId} />
|
||||
))
|
||||
}
|
||||
</ScrollableList>
|
||||
</div>
|
||||
<div className={[_s.default, _s.flexNormal].join(' ')}>
|
||||
<ScrollableList scrollKey='group-collection-column-2'>
|
||||
{
|
||||
groupIds.slice(halfCount, groupIds.size).map((groupId, i) => (
|
||||
<GroupCollectionItem key={`group-collection-item-${i}`} id={groupId} />
|
||||
))
|
||||
}
|
||||
</ScrollableList>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { FormattedMessage } from 'react-intl'
|
||||
import { isEqual } from 'lodash'
|
||||
import isEqual from 'lodash.isequal'
|
||||
import { expandHashtagTimeline, clearTimeline } from '../actions/timelines'
|
||||
import { connectHashtagStream } from '../actions/streaming'
|
||||
import StatusListContainer from '../containers/status_list_container'
|
||||
|
@ -21,7 +21,7 @@ class HashtagTimeline extends PureComponent {
|
|||
}
|
||||
|
||||
title = () => {
|
||||
let title = [this.props.params.id]
|
||||
const title = [this.props.params.id]
|
||||
|
||||
if (this.additionalFor('any')) {
|
||||
title.push(' ',
|
||||
|
@ -29,7 +29,7 @@ class HashtagTimeline extends PureComponent {
|
|||
key='any'
|
||||
id='hashtag.column_header.tag_mode.any'
|
||||
values={{
|
||||
additional: this.additionalFor('any')
|
||||
additional: this.additionalFor('any'),
|
||||
}}
|
||||
defaultMessage='or {additional}'
|
||||
/>
|
||||
|
@ -42,7 +42,7 @@ class HashtagTimeline extends PureComponent {
|
|||
key='all'
|
||||
id='hashtag.column_header.tag_mode.all'
|
||||
values={{
|
||||
additional: this.additionalFor('all')
|
||||
additional: this.additionalFor('all'),
|
||||
}}
|
||||
defaultMessage='and {additional}'
|
||||
/>
|
||||
|
@ -55,7 +55,7 @@ class HashtagTimeline extends PureComponent {
|
|||
key='none'
|
||||
id='hashtag.column_header.tag_mode.none'
|
||||
values={{
|
||||
additional: this.additionalFor('none')
|
||||
additional: this.additionalFor('none'),
|
||||
}}
|
||||
defaultMessage='without {additional}'
|
||||
/>
|
||||
|
@ -76,13 +76,13 @@ class HashtagTimeline extends PureComponent {
|
|||
}
|
||||
|
||||
_subscribe (dispatch, id, tags = {}) {
|
||||
let any = (tags.any || []).map(tag => tag.value)
|
||||
let all = (tags.all || []).map(tag => tag.value)
|
||||
let none = (tags.none || []).map(tag => tag.value);
|
||||
const any = (tags.any || []).map(tag => tag.value)
|
||||
const all = (tags.all || []).map(tag => tag.value)
|
||||
const 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)
|
||||
const 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
|
||||
|
|
|
@ -5,7 +5,7 @@ import { closeOnboarding } from '../actions/onboarding';
|
|||
|
||||
// : todo :
|
||||
|
||||
class FrameWelcome extends Component {
|
||||
class FrameWelcome extends React.Component {
|
||||
static propTypes = {
|
||||
domain: PropTypes.string.isRequired,
|
||||
onNext: PropTypes.func.isRequired,
|
||||
|
@ -45,7 +45,7 @@ class FrameWelcome extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
class FrameFederation extends Component {
|
||||
class FrameFederation extends React.Component {
|
||||
static propTypes = {
|
||||
onNext: PropTypes.func.isRequired,
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ class FrameFederation extends Component {
|
|||
}
|
||||
};
|
||||
|
||||
class FrameInteractions extends Component {
|
||||
class FrameInteractions extends React.Component {
|
||||
static propTypes = {
|
||||
onNext: PropTypes.func.isRequired,
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { FormattedMessage } from 'react-intl'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { debounce } from 'lodash'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { fetchFavoritedStatuses, expandFavoritedStatuses } from '../actions/favorites'
|
||||
import { meUsername } from '../initial_state'
|
||||
import StatusList from '../components/status_list'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { injectIntl, FormattedMessage } from 'react-intl'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { debounce } from 'lodash'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { fetchMutes, expandMutes } from '../actions/mutes'
|
||||
import AccountContainer from '../containers/account_container'
|
||||
import ColumnIndicator from '../components/column_indicator'
|
||||
|
|
|
@ -3,7 +3,7 @@ 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 debounce from 'lodash.debounce'
|
||||
import {
|
||||
expandNotifications,
|
||||
scrollTopNotifications,
|
||||
|
|
|
@ -50,7 +50,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
|
||||
onReply (status, router) {
|
||||
dispatch((_, getState) => {
|
||||
let state = getState();
|
||||
const state = getState();
|
||||
if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: intl.formatMessage(messages.replyMessage),
|
||||
|
|
|
@ -33,7 +33,7 @@ import StatusContainer from '../../containers/status_container'
|
|||
import { textForScreenReader, defaultMediaVisibility } from '../../components/status/status'
|
||||
import ColumnIndicator from '../../components/column_indicator'
|
||||
import Block from '../../components/block'
|
||||
import Comment from '../../components/comment'
|
||||
import CommentList from '../../components/comment_list'
|
||||
|
||||
const messages = defineMessages({
|
||||
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
|
||||
|
@ -57,22 +57,51 @@ const makeMapStateToProps = () => {
|
|||
username: props.params.username,
|
||||
})
|
||||
|
||||
// : todo : if is comment (i.e. if any ancestorsIds) use comment not status
|
||||
|
||||
let ancestorsIds = Immutable.List()
|
||||
let descendantsIds = Immutable.List();
|
||||
let descendantsIds = Immutable.List()
|
||||
|
||||
if (status) {
|
||||
ancestorsIds = ancestorsIds.withMutations(mutable => {
|
||||
let id = status.get('in_reply_to_id');
|
||||
// ancestorsIds = ancestorsIds.withMutations(mutable => {
|
||||
// let id = status.get('in_reply_to_id');
|
||||
|
||||
while (id) {
|
||||
mutable.unshift(id);
|
||||
id = state.getIn(['contexts', 'inReplyTos', id]);
|
||||
// while (id) {
|
||||
// mutable.unshift(id);
|
||||
// id = state.getIn(['contexts', 'inReplyTos', id]);
|
||||
// }
|
||||
// });
|
||||
|
||||
// // ONLY Direct descendants
|
||||
// descendantsIds = state.getIn(['contexts', 'replies', status.get('id')])
|
||||
|
||||
let indent = -1
|
||||
descendantsIds = descendantsIds.withMutations(mutable => {
|
||||
const ids = [status.get('id')]
|
||||
|
||||
while (ids.length > 0) {
|
||||
let id = ids.shift();
|
||||
const replies = state.getIn(['contexts', 'replies', id])
|
||||
|
||||
if (status.get('id') !== id) {
|
||||
mutable.push(Immutable.Map({
|
||||
statusId: id,
|
||||
indent: indent,
|
||||
}))
|
||||
}
|
||||
|
||||
if (replies) {
|
||||
replies.reverse().forEach(reply => {
|
||||
ids.unshift(reply)
|
||||
});
|
||||
|
||||
// ONLY Direct descendants
|
||||
descendantsIds = state.getIn(['contexts', 'replies', status.get('id')])
|
||||
indent++
|
||||
indent = Math.min(2, indent)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
console.log("descendantsIds:", descendantsIds)
|
||||
|
||||
return {
|
||||
status,
|
||||
|
@ -338,6 +367,7 @@ class Status extends ImmutablePureComponent {
|
|||
|
||||
renderChildren(list) {
|
||||
console.log("list:", list)
|
||||
return null
|
||||
// : todo : comments
|
||||
return list.map(id => (
|
||||
<Comment
|
||||
|
@ -383,9 +413,9 @@ class Status extends ImmutablePureComponent {
|
|||
return <ColumnIndicator type='loading' />
|
||||
}
|
||||
|
||||
if (ancestorsIds && ancestorsIds.size > 0) {
|
||||
ancestors = this.renderChildren(ancestorsIds)
|
||||
}
|
||||
// if (ancestorsIds && ancestorsIds.size > 0) {
|
||||
// ancestors = this.renderChildren(ancestorsIds)
|
||||
// }
|
||||
|
||||
if (descendantsIds && descendantsIds.size > 0) {
|
||||
descendants = this.renderChildren(descendantsIds)
|
||||
|
@ -434,7 +464,7 @@ class Status extends ImmutablePureComponent {
|
|||
<div className={[_s.default, _s.mr10, _s.ml10, _s.mb10, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')}/>
|
||||
}
|
||||
|
||||
{descendants}
|
||||
<CommentList descendants={descendantsIds} />
|
||||
</Block>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -3,7 +3,7 @@ import BundleColumnError from '../../../components/bundle_column_error'
|
|||
import Bundle from './bundle'
|
||||
import { me } from '../../../initial_state'
|
||||
|
||||
export default class WrappedRoute extends Component {
|
||||
export default class WrappedRoute extends PureComponent {
|
||||
static propTypes = {
|
||||
component: PropTypes.func.isRequired,
|
||||
page: PropTypes.func.isRequired,
|
||||
|
|
|
@ -5,11 +5,7 @@ import { default as GabSocial, store } from './containers/gabsocial';
|
|||
import ReactDOM from 'react-dom';
|
||||
import ready from './ready';
|
||||
|
||||
const perf = require('./performance');
|
||||
|
||||
function main() {
|
||||
perf.start('main()');
|
||||
|
||||
// : todo :
|
||||
// if (window.history && history.replaceState) {
|
||||
// const { pathname, search, hash } = window.location;
|
||||
|
@ -30,7 +26,6 @@ function main() {
|
|||
require('offline-plugin/runtime').install();
|
||||
store.dispatch(registerPushNotifications.register());
|
||||
}
|
||||
perf.stop('main()');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const createAudio = sources => {
|
||||
const audio = new Audio();
|
||||
sources.forEach(({ type, src }) => {
|
||||
const source = document.createElement('source');
|
||||
source.type = type;
|
||||
source.src = src;
|
||||
audio.appendChild(source);
|
||||
});
|
||||
return audio;
|
||||
};
|
||||
|
||||
const play = audio => {
|
||||
if (!audio.paused) {
|
||||
audio.pause();
|
||||
if (typeof audio.fastSeek === 'function') {
|
||||
audio.fastSeek(0);
|
||||
} else {
|
||||
audio.currentTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// audio.play();
|
||||
};
|
||||
|
||||
export default function soundsMiddleware() {
|
||||
const soundCache = {
|
||||
boop: createAudio([
|
||||
{
|
||||
src: '/sounds/boop.ogg',
|
||||
type: 'audio/ogg',
|
||||
},
|
||||
{
|
||||
src: '/sounds/boop.mp3',
|
||||
type: 'audio/mpeg',
|
||||
},
|
||||
]),
|
||||
ribbit: createAudio([
|
||||
{
|
||||
src: '/sounds/ribbit.ogg',
|
||||
type: 'audio/ogg',
|
||||
},
|
||||
{
|
||||
src: '/sounds/ribbit.mp3',
|
||||
type: 'audio/mpeg',
|
||||
},
|
||||
]),
|
||||
};
|
||||
|
||||
return () => next => action => {
|
||||
if (action.meta && action.meta.sound && soundCache[action.meta.sound]) {
|
||||
play(soundCache[action.meta.sound]);
|
||||
}
|
||||
|
||||
return next(action);
|
||||
};
|
||||
};
|
|
@ -36,31 +36,31 @@ class GroupsPage extends PureComponent {
|
|||
render() {
|
||||
const { children, isPro, onOpenGroupCreateModal } = this.props
|
||||
|
||||
let tabs = [
|
||||
const actions = []
|
||||
const tabs = [
|
||||
{
|
||||
title: 'Featured',
|
||||
to: '/groups'
|
||||
to: '/groups',
|
||||
},
|
||||
{
|
||||
title: 'New',
|
||||
to: '/groups/new'
|
||||
to: '/groups/new',
|
||||
},
|
||||
{
|
||||
title: 'My Groups',
|
||||
to: '/groups/browse/member'
|
||||
to: '/groups/browse/member',
|
||||
},
|
||||
]
|
||||
|
||||
let actions = []
|
||||
if (isPro) {
|
||||
actions = [{
|
||||
icon: 'group-add',
|
||||
actions.push({
|
||||
icon: 'add',
|
||||
onClick: onOpenGroupCreateModal,
|
||||
}]
|
||||
})
|
||||
|
||||
tabs.push({
|
||||
title: 'Admin',
|
||||
to: '/groups/browse/admin'
|
||||
to: '/groups/browse/admin',
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -82,4 +82,5 @@ class GroupsPage extends PureComponent {
|
|||
</DefaultLayout>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -31,8 +31,8 @@ class ListsPage extends PureComponent {
|
|||
title='Lists'
|
||||
actions={[
|
||||
{
|
||||
icon: 'list-add',
|
||||
onClick: onOpenListCreateModal
|
||||
icon: 'add',
|
||||
onClick: onOpenListCreateModal,
|
||||
},
|
||||
]}
|
||||
layout={(
|
||||
|
@ -48,4 +48,5 @@ class ListsPage extends PureComponent {
|
|||
</DefaultLayout>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@ import ProfileLayout from '../layouts/profile_layout'
|
|||
|
||||
const mapStateToProps = (state, { params: { username } }) => {
|
||||
const accounts = state.getIn(['accounts'])
|
||||
const account = accounts.find(acct => username.toLowerCase() == acct.getIn(['acct'], '').toLowerCase())
|
||||
const account = accounts.find(acct => username.toLowerCase() === acct.getIn(['acct'], '').toLowerCase())
|
||||
|
||||
const accountId = !!account ? account.get('id') : -1
|
||||
const isBlocked = state.getIn(['relationships', accountId, 'blocked_by'], false)
|
||||
|
@ -33,6 +33,7 @@ const mapStateToProps = (state, { params: { username } }) => {
|
|||
export default
|
||||
@connect(mapStateToProps)
|
||||
class ProfilePage extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
params: PropTypes.object.isRequired,
|
||||
|
@ -59,7 +60,7 @@ class ProfilePage extends ImmutablePureComponent {
|
|||
const {
|
||||
account,
|
||||
children,
|
||||
unavailable
|
||||
unavailable,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
|
@ -86,4 +87,5 @@ class ProfilePage extends ImmutablePureComponent {
|
|||
</ProfileLayout>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
//
|
||||
// Tools for performance debugging, only enabled in development mode.
|
||||
// Open up Chrome Dev Tools, then Timeline, then User Timing to see output.
|
||||
// Also see config/webpack/loaders/mark.js for the webpack loader marks.
|
||||
//
|
||||
|
||||
let marky;
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
if (typeof performance !== 'undefined' && performance.setResourceTimingBufferSize) {
|
||||
// Increase Firefox's performance entry limit; otherwise it's capped to 150.
|
||||
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1331135
|
||||
performance.setResourceTimingBufferSize(Infinity);
|
||||
}
|
||||
marky = require('marky');
|
||||
// allows us to easily do e.g. ReactPerf.printWasted() while debugging
|
||||
//window.ReactPerf = require('react-addons-perf');
|
||||
//window.ReactPerf.start();
|
||||
}
|
||||
|
||||
export function start(name) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
marky.mark(name);
|
||||
}
|
||||
}
|
||||
|
||||
export function stop(name) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
marky.stop(name);
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@ import {
|
|||
COMPOSE_POLL_OPTION_REMOVE,
|
||||
COMPOSE_POLL_SETTINGS_CHANGE,
|
||||
COMPOSE_SCHEDULED_AT_CHANGE,
|
||||
COMPOSE_RICH_TEXT_EDITOR_CONTROLS_VISIBILITY
|
||||
COMPOSE_RICH_TEXT_EDITOR_CONTROLS_VISIBILITY,
|
||||
} from '../actions/compose';
|
||||
import { TIMELINE_DELETE } from '../actions/timelines';
|
||||
import { STORE_HYDRATE } from '../actions/store';
|
||||
|
|
|
@ -1,17 +1,24 @@
|
|||
import { MODAL_OPEN, MODAL_CLOSE } from '../actions/modal';
|
||||
import Immutable from 'immutable'
|
||||
import {
|
||||
MODAL_OPEN,
|
||||
MODAL_CLOSE,
|
||||
} from '../actions/modal'
|
||||
|
||||
const initialState = {
|
||||
const initialState = Immutable.Map({
|
||||
modalType: null,
|
||||
modalProps: {},
|
||||
};
|
||||
modalProps: null,
|
||||
})
|
||||
|
||||
export default function modal(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case MODAL_OPEN:
|
||||
return { modalType: action.modalType, modalProps: action.modalProps };
|
||||
return state.withMutations(map => {
|
||||
map.set('modalType', action.modalType)
|
||||
map.set('modalProps', action.modalProps)
|
||||
})
|
||||
case MODAL_CLOSE:
|
||||
return initialState;
|
||||
return initialState
|
||||
default:
|
||||
return state;
|
||||
return state
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -6,16 +6,16 @@ import {
|
|||
|
||||
const initialState = Immutable.Map({
|
||||
popoverType: null,
|
||||
placement: null,
|
||||
popoverProps: null,
|
||||
})
|
||||
|
||||
export default function popoverMenu(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case POPOVER_OPEN:
|
||||
return {
|
||||
popoverType: action.popoverType,
|
||||
popoverProps: action.popoverProps,
|
||||
}
|
||||
return state.withMutations(map => {
|
||||
map.set('popoverType', action.popoverType)
|
||||
map.set('popoverProps', action.popoverProps)
|
||||
})
|
||||
case POPOVER_CLOSE:
|
||||
return initialState
|
||||
default:
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
GIF_RESULTS_FETCH_FAIL,
|
||||
GIF_CATEGORIES_FETCH_REQUEST,
|
||||
GIF_CATEGORIES_FETCH_SUCCESS,
|
||||
GIF_CATEGORIES_FETCH_FAIL
|
||||
GIF_CATEGORIES_FETCH_FAIL,
|
||||
} from '../actions/tenor'
|
||||
import { Map as ImmutableMap } from 'immutable'
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import IntlMessageFormat from 'intl-messageformat';
|
||||
import locales from './web_push_locales';
|
||||
import { unescape } from 'lodash';
|
||||
import unescape from 'lodash.unescape'
|
||||
|
||||
const MAX_NOTIFICATIONS = 5;
|
||||
const GROUP_TAG = 'tag';
|
||||
|
|
|
@ -3,13 +3,11 @@ import thunk from 'redux-thunk';
|
|||
import appReducer from '../reducers';
|
||||
import loadingBarMiddleware from '../middleware/loading_bar';
|
||||
import errorsMiddleware from '../middleware/errors';
|
||||
import soundsMiddleware from '../middleware/sounds';
|
||||
|
||||
export default function configureStore() {
|
||||
return createStore(appReducer, compose(applyMiddleware(
|
||||
thunk,
|
||||
loadingBarMiddleware({ promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'] }),
|
||||
errorsMiddleware(),
|
||||
soundsMiddleware()
|
||||
), window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f));
|
||||
};
|
||||
|
|
|
@ -58,7 +58,7 @@ export const getWindowDimension = () => {
|
|||
const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream
|
||||
|
||||
let userTouching = false
|
||||
let listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false
|
||||
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false
|
||||
|
||||
function touchListener() {
|
||||
userTouching = true
|
||||
|
|
|
@ -33,7 +33,6 @@ function main ( ) {
|
|||
//(Rjc) 2019-05-24 defined but never used
|
||||
// const React = require('react');
|
||||
const ReactDOM = require('react-dom');
|
||||
const Rellax = require('rellax');
|
||||
const createHistory = require('history').createBrowserHistory;
|
||||
|
||||
const scrollToDetailedStatus = () => {
|
||||
|
@ -106,12 +105,6 @@ function main ( ) {
|
|||
scrollToDetailedStatus();
|
||||
}
|
||||
|
||||
const parallaxComponents = document.querySelectorAll('.parallax');
|
||||
|
||||
if (parallaxComponents.length > 0 ) {
|
||||
new Rellax('.parallax', { speed: -1 });
|
||||
}
|
||||
|
||||
if (document.body.classList.contains('with-modals')) {
|
||||
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
||||
const scrollbarWidthStyle = document.createElement('style');
|
||||
|
|
|
@ -328,6 +328,10 @@ body {
|
|||
background-color: #36e991;
|
||||
}
|
||||
|
||||
.backgroundColorBrandLightOpaque_onHover:hover {
|
||||
background-color: rgba(54,233,145, 0.125)
|
||||
}
|
||||
|
||||
.backgroundColorBrand {
|
||||
background-color: #21cf7a;
|
||||
}
|
||||
|
@ -392,6 +396,10 @@ body {
|
|||
fill: #21cf7a;
|
||||
}
|
||||
|
||||
.fillColorBrand_onHover:hover {
|
||||
fill: #21cf7a;
|
||||
}
|
||||
|
||||
.fillColorSecondary {
|
||||
fill: #666;
|
||||
}
|
||||
|
@ -472,8 +480,8 @@ body {
|
|||
max-height: 80vh;
|
||||
}
|
||||
|
||||
.heightMax60PX {
|
||||
max-height: 60px;
|
||||
.heightMax56PX {
|
||||
max-height: 56px;
|
||||
}
|
||||
|
||||
.heightMin50VH {
|
||||
|
@ -512,6 +520,10 @@ body {
|
|||
height: 1px;
|
||||
}
|
||||
|
||||
.height40PX {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.height50PX {
|
||||
height: 50px;
|
||||
}
|
||||
|
@ -858,6 +870,10 @@ body {
|
|||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mb5 {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.mt10 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
|
|
@ -85,8 +85,6 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
|||
|
||||
def favourites_count
|
||||
if instance_options && instance_options[:unfavourite]
|
||||
# Decrement counter
|
||||
# https://github.com/tootsuite/mastodon/issues/3166
|
||||
object.favourites_count - 1
|
||||
else
|
||||
object.favourites_count
|
||||
|
|
|
@ -26,7 +26,6 @@ module.exports = (api) => {
|
|||
case 'production':
|
||||
envOptions.debug = false;
|
||||
config.plugins.push(...[
|
||||
'lodash',
|
||||
[
|
||||
'transform-react-remove-prop-types',
|
||||
{
|
||||
|
|
|
@ -14,12 +14,6 @@ const extensionGlob = `**/*{${settings.extensions.join(',')}}*`;
|
|||
const entryPath = join(settings.source_path, settings.source_entry_path);
|
||||
const packPaths = sync(join(entryPath, extensionGlob));
|
||||
|
||||
console.log("localePackPaths", localePackPaths);
|
||||
console.log("packPaths:", packPaths);
|
||||
console.log("env:", env);
|
||||
console.log("settings:", settings);
|
||||
console.log("output:", output);
|
||||
|
||||
module.exports = {
|
||||
entry: Object.assign(
|
||||
packPaths.reduce((map, entry) => {
|
||||
|
@ -70,11 +64,10 @@ module.exports = {
|
|||
plugins: [
|
||||
new webpack.ProvidePlugin({
|
||||
React: 'react',
|
||||
Component: ['react', 'Component'],
|
||||
PureComponent: ['react', 'PureComponent'],
|
||||
connect: ['react-redux', 'connect'],
|
||||
PropTypes: 'prop-types',
|
||||
_s: `${resolve(settings.source_path)}/styles/global.css`
|
||||
_s: `${resolve(settings.source_path)}/styles/global.css`,
|
||||
}),
|
||||
new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(env))),
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
|
|
182
package.json
182
package.json
|
@ -10,7 +10,6 @@
|
|||
"build:production": "cross-env RAILS_ENV=production NODE_ENV=production ./bin/webpack",
|
||||
"manage:translations": "node ./config/webpack/translationRunner.js",
|
||||
"start": "node ./streaming/index.js",
|
||||
"storybook": "start-storybook",
|
||||
"test": "${npm_execpath} run test:lint && ${npm_execpath} run test:jest",
|
||||
"test:lint": "eslint --ext=js .",
|
||||
"test:jest": "cross-env NODE_ENV=test jest --coverage",
|
||||
|
@ -20,9 +19,6 @@
|
|||
"type": "git",
|
||||
"url": "https://code.gab.com/gab/social/gab-social"
|
||||
},
|
||||
"sideEffects": [
|
||||
"*.scss"
|
||||
],
|
||||
"browserslist": [
|
||||
"last 2 versions",
|
||||
"IE >= 11",
|
||||
|
@ -62,6 +58,71 @@
|
|||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@clusterws/cws": "^0.14.0",
|
||||
"array-includes": "^3.0.3",
|
||||
"axios": "^0.19.0",
|
||||
"blurhash": "^1.0.0",
|
||||
"classnames": "^2.2.5",
|
||||
"detect-passive-events": "^1.0.2",
|
||||
"dotenv": "^8.0.0",
|
||||
"draft-js": "^0.11.4",
|
||||
"emoji-mart": "Gargron/emoji-mart#build",
|
||||
"es6-symbol": "^3.1.1",
|
||||
"escape-html": "^1.0.3",
|
||||
"exif-js": "^2.3.0",
|
||||
"express": "^4.17.1",
|
||||
"glob": "^7.1.1",
|
||||
"http-link-header": "^1.0.2",
|
||||
"immutable": "^3.8.2",
|
||||
"intersection-observer": "^0.5.1",
|
||||
"intl": "^1.2.5",
|
||||
"intl-messageformat": "^2.2.0",
|
||||
"is-nan": "^1.2.1",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"lodash.isobject": "^3.0.2",
|
||||
"lodash.pick": "^4.4.0",
|
||||
"lodash.sample": "^4.2.1",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"lodash.unescape": "^4.0.1",
|
||||
"npmlog": "^4.1.2",
|
||||
"object-assign": "^4.1.1",
|
||||
"object-fit-images": "^3.2.3",
|
||||
"object.values": "^1.1.0",
|
||||
"offline-plugin": "^5.0.7",
|
||||
"pg": "^6.4.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"punycode": "^2.1.0",
|
||||
"rails-ujs": "^5.2.3",
|
||||
"react": "^16.13.1",
|
||||
"react-datepicker": "^2.14.1",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-hotkeys": "^1.1.4",
|
||||
"react-immutable-proptypes": "^2.1.0",
|
||||
"react-immutable-pure-component": "^1.1.1",
|
||||
"react-intl": "^2.9.0",
|
||||
"react-motion": "^0.5.2",
|
||||
"react-popper": "^1.3.7",
|
||||
"react-redux": "^6.0.1",
|
||||
"react-redux-loading-bar": "^4.0.8",
|
||||
"react-router-dom": "^4.1.1",
|
||||
"react-router-scroll-4": "^1.0.0-beta.1",
|
||||
"react-stickynode": "^2.1.1",
|
||||
"react-swipeable-views": "^0.13.0",
|
||||
"redis": "^2.7.1",
|
||||
"redux": "^4.0.1",
|
||||
"redux-immutable": "^4.0.0",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"requestidlecallback": "^0.3.0",
|
||||
"reselect": "^4.0.0",
|
||||
"stringz": "^1.0.0",
|
||||
"substring-trie": "^1.0.2",
|
||||
"throng": "^4.0.0",
|
||||
"tiny-queue": "^0.2.1",
|
||||
"uuid": "^3.1.0",
|
||||
"websocket.js": "^0.1.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.3.4",
|
||||
"@babel/plugin-proposal-class-properties": "^7.3.4",
|
||||
"@babel/plugin-proposal-decorators": "^7.3.0",
|
||||
|
@ -74,111 +135,19 @@
|
|||
"@babel/preset-env": "^7.3.4",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/runtime": "^7.3.4",
|
||||
"@clusterws/cws": "^0.14.0",
|
||||
"array-includes": "^3.0.3",
|
||||
"autoprefixer": "^9.5.1",
|
||||
"axios": "^0.19.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-jest": "^24.8.0",
|
||||
"babel-loader": "^8.0.5",
|
||||
"babel-plugin-lodash": "^3.3.4",
|
||||
"babel-plugin-preval": "^3.0.1",
|
||||
"babel-plugin-react-intl": "^3.1.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"blurhash": "^1.0.0",
|
||||
"classnames": "^2.2.5",
|
||||
"compression-webpack-plugin": "^2.0.0",
|
||||
"cron": "^1.8.2",
|
||||
"cross-env": "^5.1.4",
|
||||
"css-loader": "^2.1.1",
|
||||
"cssnano": "^4.1.10",
|
||||
"detect-passive-events": "^1.0.2",
|
||||
"dotenv": "^8.0.0",
|
||||
"draft-js": "^0.11.4",
|
||||
"emoji-mart": "Gargron/emoji-mart#build",
|
||||
"es6-symbol": "^3.1.1",
|
||||
"escape-html": "^1.0.3",
|
||||
"exif-js": "^2.3.0",
|
||||
"express": "^4.17.1",
|
||||
"file-loader": "^3.0.1",
|
||||
"glob": "^7.1.1",
|
||||
"http-link-header": "^1.0.2",
|
||||
"immutable": "^3.8.2",
|
||||
"imports-loader": "^0.8.0",
|
||||
"intersection-observer": "^0.5.1",
|
||||
"intl": "^1.2.5",
|
||||
"intl-messageformat": "^2.2.0",
|
||||
"intl-relativeformat": "^2.2.0",
|
||||
"is-nan": "^1.2.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
"lodash": "^4.7.11",
|
||||
"lodash.isobject": "^3.0.2",
|
||||
"mark-loader": "^0.1.6",
|
||||
"marky": "^1.2.1",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"moment": "^2.24.0",
|
||||
"npmlog": "^4.1.2",
|
||||
"object-assign": "^4.1.1",
|
||||
"object-fit-images": "^3.2.3",
|
||||
"object.values": "^1.1.0",
|
||||
"offline-plugin": "^5.0.7",
|
||||
"path-complete-extname": "^1.0.0",
|
||||
"pg": "^6.4.0",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"postcss-object-fit-images": "^1.1.2",
|
||||
"prop-types": "^15.5.10",
|
||||
"punycode": "^2.1.0",
|
||||
"rails-ujs": "^5.2.3",
|
||||
"react": "^16.12.0",
|
||||
"react-contenteditable": "^3.3.3",
|
||||
"react-datepicker": "^2.14.1",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-hotkeys": "^1.1.4",
|
||||
"react-immutable-proptypes": "^2.1.0",
|
||||
"react-immutable-pure-component": "^1.1.1",
|
||||
"react-intl": "^2.9.0",
|
||||
"react-masonry-infinite": "^1.2.2",
|
||||
"react-motion": "^0.5.2",
|
||||
"react-notification": "^6.8.4",
|
||||
"react-overlays": "^0.8.3",
|
||||
"react-popper": "^1.3.7",
|
||||
"react-redux": "^6.0.1",
|
||||
"react-redux-loading-bar": "^4.0.8",
|
||||
"react-router-dom": "^4.1.1",
|
||||
"react-router-scroll-4": "^1.0.0-beta.1",
|
||||
"react-stickynode": "^2.1.1",
|
||||
"react-swipeable-views": "^0.13.0",
|
||||
"react-textarea-autosize": "^7.1.0",
|
||||
"react-toggle": "^4.0.1",
|
||||
"redis": "^2.7.1",
|
||||
"redux": "^4.0.1",
|
||||
"redux-immutable": "^4.0.0",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"rellax": "^1.7.1",
|
||||
"requestidlecallback": "^0.3.0",
|
||||
"reselect": "^4.0.0",
|
||||
"rimraf": "^2.6.3",
|
||||
"sanitize-html": "^1.22.0",
|
||||
"sass": "^1.20.3",
|
||||
"sass-loader": "^7.0.3",
|
||||
"sass-resources-loader": "^2.0.1",
|
||||
"stringz": "^1.0.0",
|
||||
"style-loader": "^1.1.3",
|
||||
"substring-trie": "^1.0.2",
|
||||
"throng": "^4.0.0",
|
||||
"tiny-queue": "^0.2.1",
|
||||
"uglifyjs-webpack-plugin": "^2.1.2",
|
||||
"uuid": "^3.1.0",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-assets-manifest": "^3.1.1",
|
||||
"webpack-bundle-analyzer": "^3.1.0",
|
||||
"webpack-cli": "^3.3.2",
|
||||
"webpack-merge": "^4.2.1",
|
||||
"websocket.js": "^0.1.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-jest": "^24.8.0",
|
||||
"enzyme": "^3.8.0",
|
||||
"enzyme-adapter-react-16": "^1.7.1",
|
||||
"eslint": "^5.11.1",
|
||||
|
@ -186,12 +155,27 @@
|
|||
"eslint-plugin-jsx-a11y": "~6.2.1",
|
||||
"eslint-plugin-promise": "~4.1.1",
|
||||
"eslint-plugin-react": "~7.12.1",
|
||||
"file-loader": "^3.0.1",
|
||||
"imports-loader": "^0.8.0",
|
||||
"jest": "^24.8.0",
|
||||
"node-sass": "^4.13.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
"mark-loader": "^0.1.6",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"path-complete-extname": "^1.0.0",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"postcss-object-fit-images": "^1.1.2",
|
||||
"raf": "^3.4.1",
|
||||
"react-intl-translations-manager": "^5.0.3",
|
||||
"react-test-renderer": "^16.7.0",
|
||||
"rimraf": "^2.6.3",
|
||||
"uglifyjs-webpack-plugin": "^2.1.2",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-assets-manifest": "^3.1.1",
|
||||
"webpack-bundle-analyzer": "^3.1.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.10.1",
|
||||
"webpack-merge": "^4.2.1",
|
||||
"yargs": "^12.0.5"
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue