Progress
This commit is contained in:
@@ -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,19 +173,19 @@ 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 :
|
||||
// : hack :
|
||||
//Prepend http:// to urls in status that don't have protocol
|
||||
status = status.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}`
|
||||
})
|
||||
// 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());
|
||||
}
|
||||
|
||||
@@ -167,10 +155,10 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
|
||||
done();
|
||||
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
|
||||
@@ -268,7 +256,7 @@ export function markReadNotifications() {
|
||||
const last_read = getState().getIn(['notifications', 'lastRead']);
|
||||
|
||||
if (top_notification && top_notification > last_read) {
|
||||
api(getState).post('/api/v1/notifications/mark_read', {id: top_notification}).then(response => {
|
||||
api(getState).post('/api/v1/notifications/mark_read', { id: top_notification }).then(response => {
|
||||
dispatch({
|
||||
type: NOTIFICATIONS_MARK_READ,
|
||||
notification: top_notification,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -38,12 +38,12 @@ export const fetchGifResults = () => {
|
||||
const searchText = getState().getIn(['tenor', 'searchText'], '');
|
||||
|
||||
axios.get(`https://api.tenor.com/v1/search?q=${searchText}&media_filter=minimal&limit=30&key=${tenorkey}`)
|
||||
.then((response) => {
|
||||
console.log("response:", response)
|
||||
dispatch(fetchGifResultsSuccess(response.data.results))
|
||||
}).catch(function (error) {
|
||||
dispatch(fetchGifResultsFail(error))
|
||||
})
|
||||
.then((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]');
|
||||
|
||||
28
app/javascript/gabsocial/assets/hidden_icon.js
Normal file
28
app/javascript/gabsocial/assets/hidden_icon.js
Normal file
@@ -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'
|
||||
@@ -83,39 +81,39 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
if (e.which === 229 || e.isComposing) return;
|
||||
|
||||
switch (e.key) {
|
||||
case 'Escape':
|
||||
if (suggestions.size === 0 || suggestionsHidden) {
|
||||
document.querySelector('.ui').parentElement.focus();
|
||||
} else {
|
||||
e.preventDefault();
|
||||
this.setState({ suggestionsHidden: true });
|
||||
}
|
||||
case 'Escape':
|
||||
if (suggestions.size === 0 || suggestionsHidden) {
|
||||
document.querySelector('.ui').parentElement.focus();
|
||||
} else {
|
||||
e.preventDefault();
|
||||
this.setState({ suggestionsHidden: true });
|
||||
}
|
||||
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });
|
||||
}
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });
|
||||
}
|
||||
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });
|
||||
}
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });
|
||||
}
|
||||
|
||||
break;
|
||||
case 'Enter':
|
||||
case 'Tab':
|
||||
// Select suggestion
|
||||
if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));
|
||||
}
|
||||
break;
|
||||
case 'Enter':
|
||||
case 'Tab':
|
||||
// Select suggestion
|
||||
if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
if (e.defaultPrevented || !this.props.onKeyDown) return;
|
||||
@@ -210,7 +208,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
id,
|
||||
maxLength,
|
||||
textarea,
|
||||
prependIcon
|
||||
prependIcon,
|
||||
} = this.props
|
||||
|
||||
const { suggestionsHidden } = this.state
|
||||
@@ -270,7 +268,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
onPaste={this.onPaste}
|
||||
aria-autocomplete='list'
|
||||
/> */ }
|
||||
|
||||
|
||||
{ /*
|
||||
<Textarea
|
||||
className={_s.default}
|
||||
@@ -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'
|
||||
onClick={() => action.onClick() }
|
||||
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>
|
||||
</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>
|
||||
{
|
||||
descendants.map((descendant, i) => (
|
||||
<Comment
|
||||
key={`comment-${descendant.get('statusId')}-${i}`}
|
||||
id={descendant.get('statusId')}
|
||||
indent={descendant.get('indent')}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</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,35 +70,52 @@ class GroupCollectionItem extends ImmutablePureComponent {
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={outsideClasses}>
|
||||
<div className={_s.default}>
|
||||
<NavLink
|
||||
to={`/groups/${group.get('id')}`}
|
||||
className={navLinkClasses}
|
||||
>
|
||||
<Image
|
||||
src={group.get('cover')}
|
||||
alt={group.get('title')}
|
||||
height={imageHeight}
|
||||
/>
|
||||
{
|
||||
!!coverSrc &&
|
||||
<Image
|
||||
src={coverSrc}
|
||||
alt={group.get('title')}
|
||||
className={_s.height158PX}
|
||||
/>
|
||||
}
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.positionAbsolute, _s.top0, _s.right0, _s.pt10, _s.mr10].join(' ')}>
|
||||
<Text
|
||||
badge
|
||||
className={_s.backgroundColorWhite}
|
||||
size='extraSmall'
|
||||
color='brand'
|
||||
>
|
||||
{intl.formatMessage(messages.member)}
|
||||
</Text>
|
||||
<Text
|
||||
badge
|
||||
className={[_s.backgroundColorBlack, _s.ml5].join(' ')}
|
||||
size='extraSmall'
|
||||
color='white'
|
||||
>
|
||||
{intl.formatMessage(messages.admin)}
|
||||
</Text>
|
||||
</div>
|
||||
{
|
||||
!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}
|
||||
size='extraSmall'
|
||||
color='brand'
|
||||
>
|
||||
{intl.formatMessage(messages.member)}
|
||||
</Text>
|
||||
}
|
||||
{
|
||||
isAdmin &&
|
||||
<Text
|
||||
badge
|
||||
className={[_s.backgroundColorBlack, _s.ml5].join(' ')}
|
||||
size='extraSmall'
|
||||
color='white'
|
||||
>
|
||||
{intl.formatMessage(messages.admin)}
|
||||
</Text>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div className={[_s.default, _s.px10, _s.my10].join(' ')}>
|
||||
<Text color='primary' size='medium' weight='bold'>
|
||||
@@ -113,14 +126,12 @@ class GroupCollectionItem extends ImmutablePureComponent {
|
||||
<Text color='secondary' size='small'>
|
||||
{shortNumberFormat(group.get('member_count'))}
|
||||
|
||||
{intl.formatMessage(messages.members)}
|
||||
{intl.formatMessage(messages.members)}
|
||||
</Text>
|
||||
<DotTextSeperator />
|
||||
<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}
|
||||
>
|
||||
<Image
|
||||
src={group.get('cover')}
|
||||
alt={group.get('title')}
|
||||
className={imageClasses}
|
||||
/>
|
||||
|
||||
{
|
||||
(!!coverSrc || slim) &&
|
||||
<Image
|
||||
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'
|
||||
@@ -64,70 +65,71 @@ import VerifiedIcon from '../assets/verified_icon'
|
||||
import WarningIcon from '../assets/warning_icon'
|
||||
|
||||
const ICONS = {
|
||||
'add': AddIcon,
|
||||
'angle-right': AngleRightIcon,
|
||||
'apps': AppsIcon,
|
||||
'audio': AudioIcon,
|
||||
'audio-mute': AudioMuteIcon,
|
||||
'back': BackIcon,
|
||||
'blockquote': BlockquoteIcon,
|
||||
'bold': BoldIcon,
|
||||
'calendar': CalendarIcon,
|
||||
'chat': ChatIcon,
|
||||
'close': CloseIcon,
|
||||
'code': CodeIcon,
|
||||
'comment': CommentIcon,
|
||||
'copy': CopyIcon,
|
||||
'dissenter': DissenterIcon,
|
||||
'donor': DonorIcon,
|
||||
'ellipsis': EllipsisIcon,
|
||||
'email': EmailIcon,
|
||||
'error': ErrorIcon,
|
||||
'fullscreen': FullscreenIcon,
|
||||
'gab-logo': GabLogoIcon,
|
||||
'gif': GifIcon,
|
||||
'globe': GlobeIcon,
|
||||
'group': GroupIcon,
|
||||
'group-add': GroupAddIcon,
|
||||
'happy': HappyIcon,
|
||||
'home': HomeIcon,
|
||||
'investor': InvestorIcon,
|
||||
'italic': ItalicIcon,
|
||||
'like': LikeIcon,
|
||||
'liked': LikedIcon,
|
||||
'link': LinkIcon,
|
||||
'list': ListIcon,
|
||||
'list-add': ListAddIcon,
|
||||
'loading': LoadingIcon,
|
||||
'lock': LockIcon,
|
||||
'lock-filled': LockFilledIcon,
|
||||
'media': MediaIcon,
|
||||
'minimize-fullscreen': MinimizeFullscreenIcon,
|
||||
'missing': MissingIcon,
|
||||
'more': MoreIcon,
|
||||
'notifications': NotificationsIcon,
|
||||
'ol-list': OLListIcon,
|
||||
'pause': PauseIcon,
|
||||
'pin': PinIcon,
|
||||
'play': PlayIcon,
|
||||
'poll': PollIcon,
|
||||
'pro': ProIcon,
|
||||
'repost': RepostIcon,
|
||||
'rich-text': RichTextIcon,
|
||||
'search': SearchIcon,
|
||||
'search-alt': SearchAltIcon,
|
||||
'share': ShareIcon,
|
||||
'shop': ShopIcon,
|
||||
'strikethrough': StrikethroughIcon,
|
||||
'subtract': SubtractIcon,
|
||||
'text-size': TextSizeIcon,
|
||||
'trends': TrendsIcon,
|
||||
'ul-list': ULListIcon,
|
||||
'underline': UnderlineIcon,
|
||||
'unlock-filled': UnlockFilledIcon,
|
||||
'verified': VerifiedIcon,
|
||||
'warning': WarningIcon,
|
||||
'': CircleIcon,
|
||||
'add': AddIcon,
|
||||
'angle-right': AngleRightIcon,
|
||||
'apps': AppsIcon,
|
||||
'audio': AudioIcon,
|
||||
'audio-mute': AudioMuteIcon,
|
||||
'back': BackIcon,
|
||||
'blockquote': BlockquoteIcon,
|
||||
'bold': BoldIcon,
|
||||
'calendar': CalendarIcon,
|
||||
'chat': ChatIcon,
|
||||
'close': CloseIcon,
|
||||
'code': CodeIcon,
|
||||
'comment': CommentIcon,
|
||||
'copy': CopyIcon,
|
||||
'dissenter': DissenterIcon,
|
||||
'donor': DonorIcon,
|
||||
'ellipsis': EllipsisIcon,
|
||||
'email': EmailIcon,
|
||||
'error': ErrorIcon,
|
||||
'fullscreen': FullscreenIcon,
|
||||
'gab-logo': GabLogoIcon,
|
||||
'gif': GifIcon,
|
||||
'globe': GlobeIcon,
|
||||
'group': GroupIcon,
|
||||
'group-add': GroupAddIcon,
|
||||
'hidden': HiddenIcon,
|
||||
'happy': HappyIcon,
|
||||
'home': HomeIcon,
|
||||
'investor': InvestorIcon,
|
||||
'italic': ItalicIcon,
|
||||
'like': LikeIcon,
|
||||
'liked': LikedIcon,
|
||||
'link': LinkIcon,
|
||||
'list': ListIcon,
|
||||
'list-add': ListAddIcon,
|
||||
'loading': LoadingIcon,
|
||||
'lock': LockIcon,
|
||||
'lock-filled': LockFilledIcon,
|
||||
'media': MediaIcon,
|
||||
'minimize-fullscreen': MinimizeFullscreenIcon,
|
||||
'missing': MissingIcon,
|
||||
'more': MoreIcon,
|
||||
'notifications': NotificationsIcon,
|
||||
'ol-list': OLListIcon,
|
||||
'pause': PauseIcon,
|
||||
'pin': PinIcon,
|
||||
'play': PlayIcon,
|
||||
'poll': PollIcon,
|
||||
'pro': ProIcon,
|
||||
'repost': RepostIcon,
|
||||
'rich-text': RichTextIcon,
|
||||
'search': SearchIcon,
|
||||
'search-alt': SearchAltIcon,
|
||||
'share': ShareIcon,
|
||||
'shop': ShopIcon,
|
||||
'strikethrough': StrikethroughIcon,
|
||||
'subtract': SubtractIcon,
|
||||
'text-size': TextSizeIcon,
|
||||
'trends': TrendsIcon,
|
||||
'ul-list': ULListIcon,
|
||||
'underline': UnderlineIcon,
|
||||
'unlock-filled': UnlockFilledIcon,
|
||||
'verified': VerifiedIcon,
|
||||
'warning': WarningIcon,
|
||||
'': CircleIcon,
|
||||
}
|
||||
|
||||
export default class Icon extends PureComponent {
|
||||
@@ -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 = {
|
||||
@@ -58,7 +61,7 @@ class Item extends ImmutablePureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
hoverToPlay () {
|
||||
hoverToPlay() {
|
||||
const { attachment } = this.props;
|
||||
return autoPlayGif === false && attachment.get('type') === 'gifv';
|
||||
}
|
||||
@@ -79,23 +82,23 @@ class Item extends ImmutablePureComponent {
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
if (this.props.attachment.get('blurhash')) {
|
||||
this._decode();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.attachment.get('blurhash') !== this.props.attachment.get('blurhash') && this.props.attachment.get('blurhash')) {
|
||||
this._decode();
|
||||
}
|
||||
}
|
||||
|
||||
_decode () {
|
||||
_decode() {
|
||||
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);
|
||||
|
||||
@@ -111,17 +114,17 @@ class Item extends ImmutablePureComponent {
|
||||
this.setState({ loaded: true });
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { attachment, index, size, standalone, displayWidth, visible, dimensions } = this.props;
|
||||
|
||||
const ar = attachment.getIn(['meta', 'small', 'aspect']);
|
||||
|
||||
let width = 100;
|
||||
let width = 100;
|
||||
let height = '100%';
|
||||
let top = '0';
|
||||
let left = 'auto';
|
||||
let top = '0';
|
||||
let left = 'auto';
|
||||
let bottom = '0';
|
||||
let right = 'auto';
|
||||
let right = 'auto';
|
||||
let float = 'left';
|
||||
let position = 'relative';
|
||||
let borderRadius = '0 0 0 0';
|
||||
@@ -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']);
|
||||
@@ -168,7 +171,7 @@ class Item extends ImmutablePureComponent {
|
||||
|
||||
const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;
|
||||
const focusY = attachment.getIn(['meta', 'focus', 'y']) || 0;
|
||||
const x = ((focusX / 2) + .5) * 100;
|
||||
const x = ((focusX / 2) + .5) * 100;
|
||||
const y = ((focusY / -2) + .5) * 100;
|
||||
|
||||
thumbnail = (
|
||||
@@ -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>
|
||||
);
|
||||
@@ -256,9 +264,11 @@ class MediaGallery extends PureComponent {
|
||||
width: this.props.defaultWidth,
|
||||
};
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
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 });
|
||||
}
|
||||
@@ -287,21 +297,19 @@ class MediaGallery extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const {
|
||||
media,
|
||||
intl,
|
||||
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} />
|
||||
}
|
||||
|
||||
<div className={[_s.default, _s.displayBlock, _s.width100PC, _s.height100PC, _s.overflowHidden].join(' ')}>
|
||||
{children}
|
||||
</div>
|
||||
{
|
||||
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']),
|
||||
})
|
||||
@@ -71,9 +70,9 @@ class PopoverBase extends ImmutablePureComponent {
|
||||
|
||||
handleKeyDown = e => {
|
||||
switch (e.key) {
|
||||
case 'Escape':
|
||||
this.handleClose()
|
||||
break
|
||||
case 'Escape':
|
||||
this.handleClose()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
@@ -95,22 +96,22 @@ class PopoverRoot extends PureComponent {
|
||||
let element
|
||||
|
||||
switch (e.key) {
|
||||
case 'ArrowDown':
|
||||
element = items[index + 1]
|
||||
if (element) element.focus()
|
||||
break
|
||||
case 'ArrowUp':
|
||||
element = items[index - 1]
|
||||
if (element) element.focus()
|
||||
break
|
||||
case 'Home':
|
||||
element = items[0]
|
||||
if (element) element.focus()
|
||||
break
|
||||
case 'End':
|
||||
element = items[items.length - 1]
|
||||
if (element) element.focus()
|
||||
break
|
||||
case 'ArrowDown':
|
||||
element = items[index + 1]
|
||||
if (element) element.focus()
|
||||
break
|
||||
case 'ArrowUp':
|
||||
element = items[index - 1]
|
||||
if (element) element.focus()
|
||||
break
|
||||
case 'Home':
|
||||
element = items[0]
|
||||
if (element) element.focus()
|
||||
break
|
||||
case 'End':
|
||||
element = items[items.length - 1]
|
||||
if (element) element.focus()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,9 +239,9 @@ 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}
|
||||
/>
|
||||
@@ -297,7 +297,7 @@ class ProfileHeader extends ImmutablePureComponent {
|
||||
className={[_s.px15].join(' ')}
|
||||
>
|
||||
Edit Profile
|
||||
</Text>
|
||||
</Text>
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -50,68 +50,60 @@ const selectUnits = delta => {
|
||||
|
||||
const getUnitDelay = units => {
|
||||
switch (units) {
|
||||
case 'second':
|
||||
return SECOND
|
||||
case 'minute':
|
||||
return MINUTE
|
||||
case 'hour':
|
||||
return HOUR
|
||||
case 'day':
|
||||
return DAY
|
||||
default:
|
||||
return MAX_DELAY
|
||||
case 'second':
|
||||
return SECOND
|
||||
case 'minute':
|
||||
return MINUTE
|
||||
case 'hour':
|
||||
return HOUR
|
||||
case 'day':
|
||||
return DAY
|
||||
default:
|
||||
return MAX_DELAY
|
||||
}
|
||||
}
|
||||
|
||||
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'
|
||||
@@ -139,14 +139,14 @@ export default class ScrollableList extends PureComponent {
|
||||
this.lastScrollWasSynthetic = false;
|
||||
}
|
||||
}, 150, {
|
||||
trailing: true,
|
||||
});
|
||||
trailing: true,
|
||||
});
|
||||
|
||||
handleWheel = throttle(() => {
|
||||
this.scrollToTopOnMouseIdle = false;
|
||||
}, 150, {
|
||||
trailing: true,
|
||||
});
|
||||
trailing: true,
|
||||
});
|
||||
|
||||
getSnapshotBeforeUpdate(prevProps) {
|
||||
const someItemInserted = React.Children.count(prevProps.children) > 0 &&
|
||||
@@ -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
|
||||
|
||||
50
app/javascript/gabsocial/components/sensitive_media_item.js
Normal file
50
app/javascript/gabsocial/components/sensitive_media_item.js
Normal file
@@ -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)
|
||||
|
||||
@@ -403,7 +403,7 @@ class Status extends ImmutablePureComponent {
|
||||
borderColorSecondary: !borderless,
|
||||
border1PX: !borderless,
|
||||
pb10: isChild && status.get('media_attachments').size === 0,
|
||||
pb5: isChild && status.get('media_attachments').size > 1,
|
||||
pb5: isChild && status.get('media_attachments').size > 1,
|
||||
cursorPointer: isChild,
|
||||
backgroundSubtle_onHover: isChild,
|
||||
})
|
||||
@@ -445,7 +445,7 @@ class Status extends ImmutablePureComponent {
|
||||
<Status status={status.get('quoted_status')} isChild />
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
!isChild &&
|
||||
<StatusActionBar status={status} {...other} />
|
||||
|
||||
@@ -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) {
|
||||
@@ -199,7 +200,7 @@ export default class Card extends ImmutablePureComponent {
|
||||
className={[_s.default, _s.cursorPointer, _s.backgroundColorOpaque, _s.radiusSmall, _s.py15, _s.px15].join(' ')}
|
||||
onClick={this.handleEmbedClick}
|
||||
>
|
||||
<Icon id={iconVariant} className={[_s.fillColorWhite].join(' ')}/>
|
||||
<Icon id={iconVariant} className={[_s.fillColorWhite].join(' ')} />
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
@@ -230,11 +231,11 @@ export default class Card extends ImmutablePureComponent {
|
||||
className={[_s.default, _s.cursorPointer, _s.flexRow, _s.overflowHidden, _s.noUnderline, _s.width100PC, _s.backgroundSubtle_onHover, _s.borderColorSecondary2, _s.border1PX, _s.radiusSmall].join(' ')}
|
||||
rel='noopener noreferrer'
|
||||
ref={this.setRef}
|
||||
>
|
||||
>
|
||||
{embed}
|
||||
{description}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -26,9 +26,9 @@ import { initReport } from '../actions/reports';
|
||||
import { openModal } from '../actions/modal';
|
||||
import { boostModal, deleteModal } from '../initial_state';
|
||||
// import { showAlertForError } from '../actions/alerts';
|
||||
import {
|
||||
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(' ')}>
|
||||
@@ -358,8 +368,8 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
!shouldCondense &&
|
||||
<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,20 +47,20 @@ class StatusVisibilityButton extends PureComponent {
|
||||
const {
|
||||
intl,
|
||||
small,
|
||||
value
|
||||
value,
|
||||
} = this.props
|
||||
|
||||
let icon;
|
||||
switch (value) {
|
||||
case 'unlisted':
|
||||
icon = 'unlock-filled'
|
||||
break;
|
||||
case 'private':
|
||||
icon = 'lock-filled'
|
||||
break;
|
||||
default:
|
||||
icon = 'globe'
|
||||
break;
|
||||
case 'unlisted':
|
||||
icon = 'unlock-filled'
|
||||
break;
|
||||
case 'private':
|
||||
icon = 'lock-filled'
|
||||
break;
|
||||
default:
|
||||
icon = 'globe'
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -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(' ')}>
|
||||
{
|
||||
groupIds.map((groupId, i) => (
|
||||
<GroupCollectionItem key={`group-collection-item-${i}`} id={groupId} />
|
||||
))
|
||||
}
|
||||
<div className={[_s.default, _s.flexNormal].join(' ')}>
|
||||
<ScrollableList scrollKey='group-collection-column-1'>
|
||||
{
|
||||
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,23 +57,52 @@ 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)
|
||||
});
|
||||
indent++
|
||||
indent = Math.min(2, indent)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ONLY Direct descendants
|
||||
descendantsIds = state.getIn(['contexts', 'replies', status.get('id')])
|
||||
})
|
||||
}
|
||||
|
||||
console.log("descendantsIds:", descendantsIds)
|
||||
|
||||
return {
|
||||
status,
|
||||
ancestorsIds,
|
||||
@@ -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);
|
||||
};
|
||||
};
|
||||
@@ -11,7 +11,7 @@ const mapStateToProps = (state) => {
|
||||
|
||||
return {
|
||||
isPro: account.get('is_pro'),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
@@ -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,19 +6,19 @@ 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,
|
||||
}
|
||||
case POPOVER_CLOSE:
|
||||
return initialState
|
||||
default:
|
||||
return state
|
||||
case POPOVER_OPEN:
|
||||
return state.withMutations(map => {
|
||||
map.set('popoverType', action.popoverType)
|
||||
map.set('popoverProps', action.popoverProps)
|
||||
})
|
||||
case POPOVER_CLOSE:
|
||||
return initialState
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -22,34 +22,34 @@ const initialState = ImmutableMap({
|
||||
|
||||
export default function (state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case GIF_RESULTS_FETCH_REQUEST:
|
||||
case GIF_CATEGORIES_FETCH_REQUEST:
|
||||
return state.set('loading', true)
|
||||
case GIF_RESULTS_FETCH_SUCCESS:
|
||||
return state.withMutations(map => {
|
||||
map.set('results', action.results);
|
||||
map.set('error', false);
|
||||
map.set('loading', false);
|
||||
});
|
||||
case GIF_CATEGORIES_FETCH_SUCCESS:
|
||||
return state.withMutations(map => {
|
||||
map.set('categories', action.categories);
|
||||
map.set('error', false);
|
||||
map.set('loading', false);
|
||||
});
|
||||
case GIF_RESULTS_FETCH_FAIL:
|
||||
case GIF_CATEGORIES_FETCH_FAIL:
|
||||
return state.withMutations(map => {
|
||||
map.set('error', !!action.error);
|
||||
map.set('loading', false);
|
||||
});
|
||||
case GIFS_CLEAR_RESULTS:
|
||||
return state.set('results', [])
|
||||
case GIF_SET_SELECTED:
|
||||
return state.set('chosenUrl', action.url)
|
||||
case GIF_CHANGE_SEARCH_TEXT:
|
||||
return state.set('searchText', action.text.trim());
|
||||
default:
|
||||
return state
|
||||
case GIF_RESULTS_FETCH_REQUEST:
|
||||
case GIF_CATEGORIES_FETCH_REQUEST:
|
||||
return state.set('loading', true)
|
||||
case GIF_RESULTS_FETCH_SUCCESS:
|
||||
return state.withMutations(map => {
|
||||
map.set('results', action.results);
|
||||
map.set('error', false);
|
||||
map.set('loading', false);
|
||||
});
|
||||
case GIF_CATEGORIES_FETCH_SUCCESS:
|
||||
return state.withMutations(map => {
|
||||
map.set('categories', action.categories);
|
||||
map.set('error', false);
|
||||
map.set('loading', false);
|
||||
});
|
||||
case GIF_RESULTS_FETCH_FAIL:
|
||||
case GIF_CATEGORIES_FETCH_FAIL:
|
||||
return state.withMutations(map => {
|
||||
map.set('error', !!action.error);
|
||||
map.set('loading', false);
|
||||
});
|
||||
case GIFS_CLEAR_RESULTS:
|
||||
return state.set('results', [])
|
||||
case GIF_SET_SELECTED:
|
||||
return state.set('chosenUrl', action.url)
|
||||
case GIF_CHANGE_SEARCH_TEXT:
|
||||
return state.set('searchText', action.text.trim());
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
};
|
||||
|
||||
@@ -51,14 +51,14 @@ export function getScreenBreakpoint(width) {
|
||||
export const getWindowDimension = () => {
|
||||
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
|
||||
const height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
|
||||
|
||||
|
||||
return { width, height }
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user