Browse Source

Progress

develop
mgabdev 1 year ago
parent
commit
bb4fcdf32d
101 changed files with 1036 additions and 1853 deletions
  1. +9
    -1
      .eslintrc.js
  2. +13
    -13
      app/javascript/gabsocial/actions/compose.js
  3. +9
    -21
      app/javascript/gabsocial/actions/notifications.js
  4. +1
    -1
      app/javascript/gabsocial/actions/settings.js
  5. +7
    -7
      app/javascript/gabsocial/actions/tenor.js
  6. +6
    -11
      app/javascript/gabsocial/actions/timelines.js
  7. +1
    -1
      app/javascript/gabsocial/api.js
  8. +28
    -0
      app/javascript/gabsocial/assets/hidden_icon.js
  9. +1
    -0
      app/javascript/gabsocial/components/account.js
  10. +10
    -10
      app/javascript/gabsocial/components/autosuggest_emoji/autosuggest_emoji.js
  11. +36
    -37
      app/javascript/gabsocial/components/autosuggest_textbox/autosuggest_textbox.js
  12. +1
    -0
      app/javascript/gabsocial/components/avatar.js
  13. +6
    -0
      app/javascript/gabsocial/components/block.js
  14. +8
    -8
      app/javascript/gabsocial/components/column_header.js
  15. +8
    -40
      app/javascript/gabsocial/components/comment.js
  16. +14
    -146
      app/javascript/gabsocial/components/comment_list.js
  17. +1
    -1
      app/javascript/gabsocial/components/display_name.js
  18. +1
    -1
      app/javascript/gabsocial/components/emoji/__tests__/emoji_index-test.js
  19. +2
    -15
      app/javascript/gabsocial/components/file_input.js
  20. +1
    -1
      app/javascript/gabsocial/components/floating_action_button.js
  21. +47
    -35
      app/javascript/gabsocial/components/group_collection_item.js
  22. +13
    -5
      app/javascript/gabsocial/components/group_list_item.js
  23. +1
    -0
      app/javascript/gabsocial/components/hashtag_item.js
  24. +67
    -64
      app/javascript/gabsocial/components/icon.js
  25. +22
    -13
      app/javascript/gabsocial/components/image.js
  26. +1
    -1
      app/javascript/gabsocial/components/intersection_observer_article.js
  27. +1
    -2
      app/javascript/gabsocial/components/link_footer.js
  28. +76
    -60
      app/javascript/gabsocial/components/media_gallery/media_gallery.js
  29. +1
    -2
      app/javascript/gabsocial/components/modal/gif_picker_modal.js
  30. +3
    -4
      app/javascript/gabsocial/components/modal/modal_base.js
  31. +2
    -2
      app/javascript/gabsocial/components/modal/modal_root.js
  32. +1
    -0
      app/javascript/gabsocial/components/modal/pro_upgrade_modal.js
  33. +5
    -6
      app/javascript/gabsocial/components/popover/popover_base.js
  34. +20
    -18
      app/javascript/gabsocial/components/popover/popover_root.js
  35. +14
    -14
      app/javascript/gabsocial/components/profile_header.js
  36. +1
    -1
      app/javascript/gabsocial/components/recursive_comment.js
  37. +23
    -31
      app/javascript/gabsocial/components/relative_timestamp.js
  38. +14
    -6
      app/javascript/gabsocial/components/scrollable_list.js
  39. +50
    -0
      app/javascript/gabsocial/components/sensitive_media_item.js
  40. +4
    -4
      app/javascript/gabsocial/components/sidebar.js
  41. +9
    -5
      app/javascript/gabsocial/components/sidebar_section_item.js
  42. +4
    -4
      app/javascript/gabsocial/components/status/status.js
  43. +7
    -6
      app/javascript/gabsocial/components/status_card.js
  44. +14
    -2
      app/javascript/gabsocial/components/status_content/status_content.js
  45. +1
    -1
      app/javascript/gabsocial/components/timeline_queue_button_header.js
  46. +6
    -4
      app/javascript/gabsocial/components/trends_item.js
  47. +1
    -1
      app/javascript/gabsocial/components/video.js
  48. +7
    -7
      app/javascript/gabsocial/containers/status_container.js
  49. +2
    -1
      app/javascript/gabsocial/containers/status_list_container.js
  50. +2
    -2
      app/javascript/gabsocial/features/account_gallery.js
  51. +1
    -1
      app/javascript/gabsocial/features/blocked_accounts.js
  52. +1
    -1
      app/javascript/gabsocial/features/blocked_domains.js
  53. +34
    -24
      app/javascript/gabsocial/features/compose/components/compose_form/compose_form.js
  54. +1
    -1
      app/javascript/gabsocial/features/compose/components/emoji_picker_button.js
  55. +1
    -1
      app/javascript/gabsocial/features/compose/components/gif_selector_button.js
  56. +0
    -23
      app/javascript/gabsocial/features/compose/components/quoted_status_preview.js
  57. +15
    -10
      app/javascript/gabsocial/features/compose/components/status_visibility_button.js
  58. +1
    -1
      app/javascript/gabsocial/features/compose/components/upload_form/upload_form.js
  59. +1
    -1
      app/javascript/gabsocial/features/compose/compose.js
  60. +3
    -2
      app/javascript/gabsocial/features/compose/containers/compose_form_container.js
  61. +0
    -8
      app/javascript/gabsocial/features/compose/containers/quoted_status_preview_container.js
  62. +3
    -3
      app/javascript/gabsocial/features/compose/util/counter.js
  63. +1
    -1
      app/javascript/gabsocial/features/follow_requests/follow_requests.js
  64. +1
    -1
      app/javascript/gabsocial/features/followers.js
  65. +1
    -1
      app/javascript/gabsocial/features/following.js
  66. +1
    -1
      app/javascript/gabsocial/features/group_members.js
  67. +1
    -1
      app/javascript/gabsocial/features/group_removed_accounts.js
  68. +24
    -5
      app/javascript/gabsocial/features/groups_collection.js
  69. +9
    -9
      app/javascript/gabsocial/features/hashtag_timeline.js
  70. +3
    -3
      app/javascript/gabsocial/features/introduction.js
  71. +1
    -1
      app/javascript/gabsocial/features/liked_statuses.js
  72. +1
    -1
      app/javascript/gabsocial/features/mutes.js
  73. +1
    -1
      app/javascript/gabsocial/features/notifications/notifications.js
  74. +1
    -1
      app/javascript/gabsocial/features/status/containers/detailed_status_container.js
  75. +45
    -15
      app/javascript/gabsocial/features/status/status.js
  76. +1
    -1
      app/javascript/gabsocial/features/ui/util/wrapped_route.js
  77. +0
    -5
      app/javascript/gabsocial/main.js
  78. +0
    -58
      app/javascript/gabsocial/middleware/sounds.js
  79. +11
    -10
      app/javascript/gabsocial/pages/groups_page.js
  80. +3
    -2
      app/javascript/gabsocial/pages/lists_page.js
  81. +4
    -2
      app/javascript/gabsocial/pages/profile_page.js
  82. +0
    -33
      app/javascript/gabsocial/performance.js
  83. +1
    -1
      app/javascript/gabsocial/reducers/compose.js
  84. +15
    -8
      app/javascript/gabsocial/reducers/modal.js
  85. +10
    -10
      app/javascript/gabsocial/reducers/popover.js
  86. +30
    -30
      app/javascript/gabsocial/reducers/tenor.js
  87. +1
    -1
      app/javascript/gabsocial/service_worker/web_push_notifications.js
  88. +0
    -2
      app/javascript/gabsocial/store/configureStore.js
  89. +2
    -2
      app/javascript/gabsocial/utils/is_mobile.js
  90. +0
    -7
      app/javascript/packs/public.js
  91. +18
    -2
      app/javascript/styles/global.css
  92. +0
    -2
      app/serializers/rest/status_serializer.rb
  93. +0
    -1
      babel.config.js
  94. +1
    -8
      config/webpack/shared.js
  95. +46
    -62
      package.json
  96. BIN
      public/sounds/boop.mp3
  97. BIN
      public/sounds/boop.ogg
  98. BIN
      public/sounds/ribbit.mp3
  99. BIN
      public/sounds/ribbit.ogg
  100. BIN
      public/sounds/ribbit.wav

+ 9
- 1
.eslintrc.js View File

@ -10,6 +10,13 @@ module.exports = {
globals: {
ATTACHMENT_HOST: false,
_s: true,
PropTypes: true,
PureComponent: true,
React: {
Component: true,
},
connect: true,
},
parser: 'babel-eslint',
@ -98,8 +105,9 @@ module.exports = {
classes: 'always',
},
],
'prefer-const': 'error',
quotes: ['error', 'single'],
semi: 'error',
semi: 'off',
strict: 'off',
'valid-typeof': 'error',


+ 13
- 13
app/javascript/gabsocial/actions/compose.js View File

@ -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),


+ 9
- 21
app/javascript/gabsocial/actions/notifications.js View File

@ -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
- 1
app/javascript/gabsocial/actions/settings.js View File

@ -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';


+ 7
- 7
app/javascript/gabsocial/actions/tenor.js View File

@ -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))
})
}
}


+ 6
- 11
app/javascript/gabsocial/actions/timelines.js View File

@ -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;
}
}


+ 1
- 1
app/javascript/gabsocial/api.js View File

@ -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
- 0
app/javascript/gabsocial/assets/hidden_icon.js View 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

+ 1
- 0
app/javascript/gabsocial/components/account.js View File

@ -93,6 +93,7 @@ class Account extends ImmutablePureComponent {
)
}
// : todo : cleanup
let buttonOptions
let buttonText


+ 10
- 10
app/javascript/gabsocial/components/autosuggest_emoji/autosuggest_emoji.js View File

@ -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>
);
)
}
}

+ 36
- 37
app/javascript/gabsocial/components/autosuggest_textbox/autosuggest_textbox.js View File

@ -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 });
}
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 '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 '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 '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;
}
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)}


+ 1
- 0
app/javascript/gabsocial/components/avatar.js View File

@ -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,


+ 6
- 0
app/javascript/gabsocial/components/block.js View File

@ -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>
)
}
}

+ 8
- 8
app/javascript/gabsocial/components/column_header.js View File

@ -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'
/>
))
}


+ 8
- 40
app/javascript/gabsocial/components/comment.js View File

@ -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


+ 14
- 146
app/javascript/gabsocial/components/comment_list.js View File

@ -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
- 1
app/javascript/gabsocial/components/display_name.js View File

@ -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
- 1
app/javascript/gabsocial/components/emoji/__tests__/emoji_index-test.js View File

@ -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';


+ 2
- 15
app/javascript/gabsocial/components/file_input.js View File

@ -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
- 1
app/javascript/gabsocial/components/floating_action_button.js View File

@ -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,


+ 47
- 35
app/javascript/gabsocial/components/group_collection_item.js View File

@ -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}
/>
<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 &&
<Image
src={coverSrc}
alt={group.get('title')}
className={_s.height158PX}
/>
}
{
!coverSrc && (isMember || isAdmin) &&
<div className={[_s.default, _s.height40PX, _s.backgroundSubtle, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')} />
}
{
(isMember || isAdmin) &&
<div className={[_s.default, _s.flexRow, _s.positionAbsolute, _s.top0, _s.right0, _s.pt10, _s.mr10].join(' ')}>
{
isMember &&
<Text
badge
className={_s.backgroundColorWhite}
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'))}
&nbsp;
{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>
)
}
}

+ 13
- 5
app/javascript/gabsocial/components/group_list_item.js View File

@ -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>
)
}
}

+ 1
- 0
app/javascript/gabsocial/components/hashtag_item.js View File

@ -45,6 +45,7 @@ export default class HashtagItem extends ImmutablePureComponent {
text
backgroundColor='none'
color='none'
title='Remove'
icon='caret-down'
iconWidth='8px'
iconHeight='8px'


+ 67
- 64
app/javascript/gabsocial/components/icon.js View File

@ -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} />
}
}

+ 22
- 13
app/javascript/gabsocial/components/image.js View File

@ -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}
/>
)
}
}

+ 1
- 1
app/javascript/gabsocial/components/intersection_observer_article.js View File

@ -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
- 2
app/javascript/gabsocial/components/link_footer.js View File

@ -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 = [
{


+ 76
- 60
app/javascript/gabsocial/components/media_gallery/media_gallery.js View File

@ -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');