diff options
Diffstat (limited to 'app')
7 files changed, 94 insertions, 78 deletions
diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js index 603aebc86..925132b07 100644 --- a/app/javascript/flavours/glitch/components/media_gallery.js +++ b/app/javascript/flavours/glitch/components/media_gallery.js @@ -132,16 +132,21 @@ class Item extends React.PureComponent { let thumbnail = ''; if (attachment.get('type') === 'image') { - const previewUrl = attachment.get('preview_url'); + const previewUrl = attachment.get('preview_url'); const previewWidth = attachment.getIn(['meta', 'small', 'width']); - const originalUrl = attachment.get('url'); - const originalWidth = attachment.getIn(['meta', 'original', 'width']); + const originalUrl = attachment.get('url'); + const originalWidth = attachment.getIn(['meta', 'original', 'width']); const hasSize = typeof originalWidth === 'number' && typeof previewWidth === 'number'; const srcSet = hasSize ? `${originalUrl} ${originalWidth}w, ${previewUrl} ${previewWidth}w` : null; - const sizes = hasSize ? `(min-width: 1025px) ${320 * (width / 100)}px, ${width}vw` : null; + const sizes = hasSize ? `(min-width: 1025px) ${320 * (width / 100)}px, ${width}vw` : null; + + const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0; + const focusY = attachment.getIn(['meta', 'focus', 'y']) || 0; + const x = ((focusX / 2) + .5) * 100; + const y = ((focusY / -2) + .5) * 100; thumbnail = ( <a @@ -150,7 +155,14 @@ class Item extends React.PureComponent { onClick={this.handleClick} target='_blank' > - <img className={letterbox ? 'letterbox' : null} src={previewUrl} srcSet={srcSet} sizes={sizes} alt={attachment.get('description')} title={attachment.get('description')} /> + <img + className={letterbox ? 'letterbox' : null} + src={previewUrl} + srcSet={srcSet} + sizes={sizes} + alt={attachment.get('description')} + title={attachment.get('description')} + style={{ objectPosition: `${x}% ${y}%` }} /> </a> ); } else if (attachment.get('type') === 'gifv') { @@ -221,30 +233,59 @@ export default class MediaGallery extends React.PureComponent { this.props.onOpenMedia(this.props.media, index); } + handleRef = (node) => { + if (node && this.isStandaloneEligible()) { + // offsetWidth triggers a layout, so only calculate when we need to + this.setState({ + width: node.offsetWidth, + }); + } + } + + isStandaloneEligible() { + const { media, standalone } = this.props; + return standalone && media.size === 1 && media.getIn([0, 'meta', 'small', 'aspect']); + } + render () { - const { - handleClick, - handleOpen, - } = this; - const { - fullwidth, - intl, - letterbox, - media, - sensitive, - standalone, - } = this.props; - const { visible } = this.state; + const { media, intl, sensitive, letterbox, fullwidth } = this.props; + const { width, visible } = this.state; const size = media.take(4).size; + + let children; + + const style = {}; + + if (this.isStandaloneEligible() && width) { + style.height = width / this.props.media.getIn([0, 'meta', 'small', 'aspect']); + } + + if (!visible) { + let warning = <FormattedMessage {...(sensitive ? messages.warning : messages.hidden)} />; + + children = ( + <button className='media-spoiler' type='button' onClick={this.handleOpen}> + <span className='media-spoiler__warning'>{warning}</span> + <span className='media-spoiler__trigger'><FormattedMessage {...messages.toggle} /></span> + </button> + ); + } else { + if (this.isStandaloneEligible()) { + children = <Item standalone attachment={media.get(0)} onClick={this.handleClick} />; + } else { + children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} index={i} size={size} letterbox={letterbox} />); + } + } + const computedClass = classNames('media-gallery', `size-${size}`, { 'full-width': fullwidth }); return ( - <div className={computedClass}> + <div className={computedClass} style={style} ref={this.handleRef}> {visible ? ( <div className='sensitive-info'> <IconButton icon='eye' - onClick={handleOpen} + onClick={this.handleOpen} overlay title={intl.formatMessage(messages.toggle_visible)} /> @@ -255,46 +296,8 @@ export default class MediaGallery extends React.PureComponent { ) : null} </div> ) : null} - {function () { - switch (true) { - case !visible: - return ( - <button - className='media-spoiler' - type='button' - onClick={handleOpen} - > - <span className='media-spoiler__warning'> - <FormattedMessage {...(sensitive ? messages.warning : messages.hidden)} /> - </span> - <span className='media-spoiler__trigger'> - <FormattedMessage {...messages.toggle} /> - </span> - </button> - ); - case standalone && media.size === 1 && !!media.getIn([0, 'meta', 'small', 'aspect']): - return ( - <Item - attachment={media.get(0)} - onClick={handleClick} - standalone - /> - ); - default: - return media.take(4).map( - (attachment, i) => ( - <Item - attachment={attachment} - index={i} - key={attachment.get('id')} - letterbox={letterbox} - onClick={handleClick} - size={size} - /> - ) - ); - } - }()} + + {children} </div> ); } diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js index e7c26d013..066499da8 100644 --- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js +++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js @@ -4,7 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import Avatar from 'flavours/glitch/components/avatar'; import DisplayName from 'flavours/glitch/components/display_name'; import StatusContent from 'flavours/glitch/components/status_content'; -import StatusGallery from 'flavours/glitch/components/media_gallery'; +import MediaGallery from 'flavours/glitch/components/media_gallery'; import AttachmentList from 'flavours/glitch/components/attachment_list'; import { Link } from 'react-router-dom'; import { FormattedDate, FormattedNumber } from 'react-intl'; @@ -69,7 +69,8 @@ export default class DetailedStatus extends ImmutablePureComponent { mediaIcon = 'video-camera'; } else { media = ( - <StatusGallery + <MediaGallery + standalone sensitive={status.get('sensitive')} media={status.get('media_attachments')} letterbox={settings.getIn(['media', 'letterbox'])} diff --git a/app/javascript/flavours/glitch/features/video/index.js b/app/javascript/flavours/glitch/features/video/index.js index 56ee9c20c..4cb5db7f5 100644 --- a/app/javascript/flavours/glitch/features/video/index.js +++ b/app/javascript/flavours/glitch/features/video/index.js @@ -29,7 +29,7 @@ const formatTime = secondsNum => { return (hours === '00' ? '' : `${hours}:`) + `${minutes}:${seconds}`; }; -const findElementPosition = el => { +export const findElementPosition = el => { let box; if (el.getBoundingClientRect && el.parentNode) { @@ -60,7 +60,7 @@ const findElementPosition = el => { }; }; -const getPointerPosition = (el, event) => { +export const getPointerPosition = (el, event) => { const position = {}; const box = findElementPosition(el); const boxW = el.offsetWidth; @@ -76,7 +76,7 @@ const getPointerPosition = (el, event) => { pageY = event.changedTouches[0].pageY; } - position.y = Math.max(0, Math.min(1, ((boxY - pageY) + boxH) / boxH)); + position.y = Math.max(0, Math.min(1, (pageY - boxY) / boxH)); position.x = Math.max(0, Math.min(1, (pageX - boxX) / boxW)); return position; diff --git a/app/javascript/flavours/glitch/styles/components/status.scss b/app/javascript/flavours/glitch/styles/components/status.scss index 1d1cf0f9e..0a022802a 100644 --- a/app/javascript/flavours/glitch/styles/components/status.scss +++ b/app/javascript/flavours/glitch/styles/components/status.scss @@ -244,9 +244,17 @@ height: 20px; overflow: hidden; text-overflow: ellipsis; - margin: 0; padding-top: 0; + &:after { + content: ""; + position: absolute; + top: 0; bottom: 0; + left: 0; right: 0; + background: linear-gradient(rgba($ui-base-color, 0), rgba($ui-base-color, 1)); + pointer-events: none; + } + a:hover { text-decoration: none; } diff --git a/app/javascript/styles/mastodon/reset.scss b/app/javascript/styles/mastodon/reset.scss index 58d4de35f..ff3b2c022 100644 --- a/app/javascript/styles/mastodon/reset.scss +++ b/app/javascript/styles/mastodon/reset.scss @@ -53,6 +53,11 @@ table { border-spacing: 0; } +::-webkit-scrollbar { + width: 12px; + height: 12px; +} + ::-webkit-scrollbar-thumb { background: lighten($ui-base-color, 4%); border: 0px none $base-border-color; diff --git a/app/views/admin/reports/_report.html.haml b/app/views/admin/reports/_report.html.haml index d266f4840..84db00ad5 100644 --- a/app/views/admin/reports/_report.html.haml +++ b/app/views/admin/reports/_report.html.haml @@ -5,18 +5,18 @@ = link_to report.target_account.acct, admin_account_path(report.target_account.id) %td.reporter = link_to report.account.acct, admin_account_path(report.account.id) - %td.comment - %span{ title: report.comment } + %td + %div{ title: report.comment } = truncate(report.comment, length: 30, separator: ' ') - %td.stats - - unless report.statuses.empty? - %span{ title: t('admin.accounts.statuses') } - = fa_icon('comment') - = report.statuses.count - - unless report.media_attachments.empty? - %span{ title: t('admin.accounts.media_attachments') } - = fa_icon('camera') - = report.media_attachments.count + %div + - unless report.statuses.empty? + %span{ title: t('admin.accounts.statuses') } + = fa_icon('comment') + = report.statuses.count + - unless report.media_attachments.empty? + %span{ title: t('admin.accounts.media_attachments') } + = fa_icon('camera') + = report.media_attachments.count %td - if report.assigned_account.nil? \- diff --git a/app/views/admin/reports/index.html.haml b/app/views/admin/reports/index.html.haml index 3b127c4fc..c3baaf6be 100644 --- a/app/views/admin/reports/index.html.haml +++ b/app/views/admin/reports/index.html.haml @@ -18,7 +18,6 @@ %th= t('admin.reports.id') %th= t('admin.reports.target') %th= t('admin.reports.reported_by') - %th= t('admin.reports.comment.label') %th= t('admin.reports.report_contents') %th= t('admin.reports.assigned') %th |