parent
9fd5c8f6d2
commit
8f6681ad7a
|
@ -3,15 +3,16 @@
|
||||||
{label}
|
{label}
|
||||||
background="var(--muted-modal-bg)"
|
background="var(--muted-modal-bg)"
|
||||||
muted="true"
|
muted="true"
|
||||||
|
clickHeaderToClose={true}
|
||||||
className="media-modal-dialog"
|
className="media-modal-dialog"
|
||||||
on:show="onShow()"
|
on:show="onShow()"
|
||||||
>
|
>
|
||||||
<div class="media-container">
|
<div class="media-container">
|
||||||
<ul class="media-scroll" ref:scroller>
|
<ul class="media-scroll" ref:scroller on:click="onImageClick(event)">
|
||||||
{#each mediaItems as media (media.id)}
|
{#each mediaItems as media (media.id)}
|
||||||
<li class="media-scroll-item">
|
<li class="media-scroll-item">
|
||||||
<div class="media-scroll-item-inner">
|
<div class="media-scroll-item-inner">
|
||||||
<div class="media-scroll-item-inner-inner">
|
<div class="media-scroll-item-image-area">
|
||||||
{#if canPinchZoom && pinchZoomMode}
|
{#if canPinchZoom && pinchZoomMode}
|
||||||
<PinchZoomable className='media-pinch-zoom' >
|
<PinchZoomable className='media-pinch-zoom' >
|
||||||
<MediaInDialog {media} />
|
<MediaInDialog {media} />
|
||||||
|
@ -24,10 +25,11 @@
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="media-controls-outside">
|
<div class="media-controls-outside" on:click="onMediaControlsClick(event)">
|
||||||
{#if canPinchZoom}
|
{#if canPinchZoom}
|
||||||
<IconButton
|
<IconButton
|
||||||
className="media-control-button media-control-button-dummy-spacer"
|
className="media-control-button media-control-button-dummy-spacer"
|
||||||
|
svgClassName="media-control-button-svg"
|
||||||
href="#fa-search"
|
href="#fa-search"
|
||||||
label=""
|
label=""
|
||||||
ariaHidden={true}
|
ariaHidden={true}
|
||||||
|
@ -37,6 +39,7 @@
|
||||||
<div class="media-controls">
|
<div class="media-controls">
|
||||||
<IconButton
|
<IconButton
|
||||||
className="media-control-button"
|
className="media-control-button"
|
||||||
|
svgClassName="media-control-button-svg"
|
||||||
disabled={scrolledItem === 0}
|
disabled={scrolledItem === 0}
|
||||||
label="Show previous media"
|
label="Show previous media"
|
||||||
href="#fa-angle-left"
|
href="#fa-angle-left"
|
||||||
|
@ -45,16 +48,18 @@
|
||||||
{#each dots as dot, i (dot.i)}
|
{#each dots as dot, i (dot.i)}
|
||||||
<IconButton
|
<IconButton
|
||||||
className="media-control-button"
|
className="media-control-button"
|
||||||
|
svgClassName="media-control-button-svg"
|
||||||
pressable={true}
|
pressable={true}
|
||||||
label="Show {nth(i)} media"
|
label="Show {nth(i)} media"
|
||||||
pressed={i === scrolledItem}
|
pressed={i === scrolledItem}
|
||||||
href={i === scrolledItem ? '#fa-circle' : '#fa-circle-o'}
|
href={i === scrolledItem ? '#fa-circle' : '#fa-circle-o'}
|
||||||
sameColorWhenPressed={true}
|
sameColorWhenPressed={true}
|
||||||
on:click="onClick(i)"
|
on:click="onButtonClick(i)"
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
<IconButton
|
<IconButton
|
||||||
className="media-control-button"
|
className="media-control-button"
|
||||||
|
svgClassName="media-control-button-svg"
|
||||||
disabled={scrolledItem === length - 1}
|
disabled={scrolledItem === length - 1}
|
||||||
label="Show next media"
|
label="Show next media"
|
||||||
href="#fa-angle-right"
|
href="#fa-angle-right"
|
||||||
|
@ -65,6 +70,7 @@
|
||||||
{#if canPinchZoom}
|
{#if canPinchZoom}
|
||||||
<IconButton
|
<IconButton
|
||||||
className="media-control-button"
|
className="media-control-button"
|
||||||
|
svgClassName="media-control-button-svg"
|
||||||
pressable={true}
|
pressable={true}
|
||||||
pressed={pinchZoomMode}
|
pressed={pinchZoomMode}
|
||||||
label={pinchZoomMode ? 'Disable pinch-zoom mode' : 'Enable pinch-zoom mode'}
|
label={pinchZoomMode ? 'Disable pinch-zoom mode' : 'Enable pinch-zoom mode'}
|
||||||
|
@ -85,7 +91,6 @@
|
||||||
.media-container {
|
.media-container {
|
||||||
height: calc(100% - 64px); /* 44px X button height + 20px padding */
|
height: calc(100% - 64px); /* 44px X button height + 20px padding */
|
||||||
width: calc(100vw);
|
width: calc(100vw);
|
||||||
padding-top: 10px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
@ -118,16 +123,16 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.media-scroll-item-inner-inner {
|
.media-scroll-item-image-area {
|
||||||
height: calc(100% - 10px);
|
height: calc(100% - 20px); /* 15px padding top + 5px padding bottom */
|
||||||
width: calc(100% - 10px);
|
width: calc(100% - 10px); /* 5px padding left + 5px padding right */
|
||||||
padding: 5px;
|
padding: 15px 5px 5px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-controls-outside {
|
.media-controls-outside {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-controls {
|
.media-controls {
|
||||||
|
@ -148,6 +153,11 @@
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global(.media-control-button-svg) {
|
||||||
|
/* ensure that click events do not fall on these svgs */
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
:global(.icon-button.media-control-button) {
|
:global(.icon-button.media-control-button) {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -197,10 +207,21 @@
|
||||||
import PinchZoomable from './PinchZoomable.html'
|
import PinchZoomable from './PinchZoomable.html'
|
||||||
import { show } from '../helpers/showDialog'
|
import { show } from '../helpers/showDialog'
|
||||||
import { oncreate as onCreateDialog } from '../helpers/onCreateDialog'
|
import { oncreate as onCreateDialog } from '../helpers/onCreateDialog'
|
||||||
|
import { close } from '../helpers/closeDialog'
|
||||||
import debounce from 'lodash-es/debounce'
|
import debounce from 'lodash-es/debounce'
|
||||||
import times from 'lodash-es/times'
|
import times from 'lodash-es/times'
|
||||||
import { smoothScroll, hasNativeSmoothScroll } from '../../../_utils/smoothScroll'
|
import { smoothScroll, hasNativeSmoothScroll } from '../../../_utils/smoothScroll'
|
||||||
import { store } from '../../../_store/store'
|
import { store } from '../../../_store/store'
|
||||||
|
import { intrinsicScale } from '../../../_thirdparty/intrinsic-scale/intrinsicScale'
|
||||||
|
import { get } from '../../../_utils/lodash-lite'
|
||||||
|
|
||||||
|
// padding for .media-scroll-item-image-area
|
||||||
|
const IMAGE_AREA_PADDING = {
|
||||||
|
top: 15,
|
||||||
|
left: 5,
|
||||||
|
right: 5,
|
||||||
|
bottom: 5
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate () {
|
oncreate () {
|
||||||
|
@ -217,7 +238,10 @@
|
||||||
computed: {
|
computed: {
|
||||||
length: ({ mediaItems }) => mediaItems.length,
|
length: ({ mediaItems }) => mediaItems.length,
|
||||||
dots: ({ length }) => times(length, i => ({ i })),
|
dots: ({ length }) => times(length, i => ({ i })),
|
||||||
canPinchZoom: ({ mediaItems }) => !mediaItems.some(media => ['video', 'audio'].includes(media.type))
|
canPinchZoom: ({ mediaItems }) => !mediaItems.some(media => ['video', 'audio'].includes(media.type)),
|
||||||
|
mediaItem: ({ mediaItems, scrolledItem }) => mediaItems[scrolledItem],
|
||||||
|
nativeWidth: ({ mediaItem }) => get(mediaItem, ['meta', 'original', 'width'], 300), // TODO: Pleroma placeholder
|
||||||
|
nativeHeight: ({ mediaItem }) => get(mediaItem, ['meta', 'original', 'height'], 200) // TODO: Pleroma placeholder
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
ModalDialog,
|
ModalDialog,
|
||||||
|
@ -242,6 +266,7 @@
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
show,
|
show,
|
||||||
|
close,
|
||||||
setupScroll () {
|
setupScroll () {
|
||||||
this.refs.scroller.addEventListener('scroll', this.onScroll)
|
this.refs.scroller.addEventListener('scroll', this.onScroll)
|
||||||
},
|
},
|
||||||
|
@ -258,7 +283,7 @@
|
||||||
let scrolledItem = Math.round((scrollLeft / scrollWidth) * length)
|
let scrolledItem = Math.round((scrollLeft / scrollWidth) * length)
|
||||||
this.set({ scrolledItem })
|
this.set({ scrolledItem })
|
||||||
},
|
},
|
||||||
onClick (i) {
|
onButtonClick (i) {
|
||||||
let { scrolledItem } = this.get()
|
let { scrolledItem } = this.get()
|
||||||
if (scrolledItem !== i) {
|
if (scrolledItem !== i) {
|
||||||
this.scrollToItem(i, true)
|
this.scrollToItem(i, true)
|
||||||
|
@ -308,6 +333,44 @@
|
||||||
},
|
},
|
||||||
togglePinchZoomMode () {
|
togglePinchZoomMode () {
|
||||||
this.set({ pinchZoomMode: !this.get().pinchZoomMode })
|
this.set({ pinchZoomMode: !this.get().pinchZoomMode })
|
||||||
|
},
|
||||||
|
onImageClick (e) {
|
||||||
|
let { nativeWidth, nativeHeight, pinchZoomMode } = this.get()
|
||||||
|
if (pinchZoomMode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let rect = this.refs.scroller.getBoundingClientRect()
|
||||||
|
// apply padding
|
||||||
|
rect = {
|
||||||
|
width: rect.width - IMAGE_AREA_PADDING.left - IMAGE_AREA_PADDING.right,
|
||||||
|
height: rect.height - IMAGE_AREA_PADDING.top - IMAGE_AREA_PADDING.bottom,
|
||||||
|
left: rect.left + IMAGE_AREA_PADDING.left,
|
||||||
|
top: rect.top + IMAGE_AREA_PADDING.top
|
||||||
|
}
|
||||||
|
let scale = intrinsicScale(rect.width, rect.height, nativeWidth, nativeHeight)
|
||||||
|
let x = e.clientX - rect.left
|
||||||
|
let y = e.clientY - rect.top
|
||||||
|
let insideImage = x >= scale.x && x <= (scale.x + scale.width) && y >= scale.y && y <= (scale.y + scale.height)
|
||||||
|
if (!insideImage) {
|
||||||
|
// close dialog when clicking outside of image
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onMediaControlsClick (e) {
|
||||||
|
let { pinchZoomMode } = this.get()
|
||||||
|
if (pinchZoomMode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let { target } = e
|
||||||
|
if (target.tagName !== 'BUTTON' && !target.classList.contains('media-controls')) {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
// close dialog when clicking on the controls but not on a button inside the controls,
|
||||||
|
// or between the buttons
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,8 +223,12 @@
|
||||||
focusX: ({ mediaItem }) => get(mediaItem, ['focusX'], 0),
|
focusX: ({ mediaItem }) => get(mediaItem, ['focusX'], 0),
|
||||||
focusY: ({ mediaItem }) => get(mediaItem, ['focusY'], 0),
|
focusY: ({ mediaItem }) => get(mediaItem, ['focusY'], 0),
|
||||||
previewSrc: ({ mediaItem }) => mediaItem.data.preview_url,
|
previewSrc: ({ mediaItem }) => mediaItem.data.preview_url,
|
||||||
nativeWidth: ({ mediaItem }) => get(mediaItem, ['data', 'meta', 'original', 'width'], 300),
|
nativeWidth: ({ mediaItem }) => (
|
||||||
nativeHeight: ({ mediaItem }) => get(mediaItem, ['data', 'meta', 'original', 'height'], 200),
|
get(mediaItem, ['data', 'meta', 'original', 'width'], 300) // TODO: Pleroma placeholder
|
||||||
|
),
|
||||||
|
nativeHeight: ({ mediaItem }) => (
|
||||||
|
get(mediaItem, ['data', 'meta', 'original', 'height'], 200) // TODO: Pleroma placeholder
|
||||||
|
),
|
||||||
shortName: ({ mediaItem }) => (
|
shortName: ({ mediaItem }) => (
|
||||||
// sometimes we no longer have the file, e.g. in a delete and redraft situation,
|
// sometimes we no longer have the file, e.g. in a delete and redraft situation,
|
||||||
// so fall back to the description if it was provided
|
// so fall back to the description if it was provided
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
ref:node
|
ref:node
|
||||||
>
|
>
|
||||||
<div class="modal-dialog-document" role="document" style="background: {background || '#000'};">
|
<div class="modal-dialog-document" role="document" style="background: {background || '#000'};">
|
||||||
<div class="modal-dialog-header">
|
<div class="modal-dialog-header" on:click="onClickHeader(event)">
|
||||||
{#if title}
|
{#if title}
|
||||||
<h1 class="modal-dialog-title">{title}</h1>
|
<h1 class="modal-dialog-title">{title}</h1>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -190,7 +190,8 @@
|
||||||
muted: false,
|
muted: false,
|
||||||
className: void 0,
|
className: void 0,
|
||||||
title: void 0,
|
title: void 0,
|
||||||
shrinkWidthToFit: false
|
shrinkWidthToFit: false,
|
||||||
|
clickHeaderToClose: false
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
backdropClass: ({ fadedIn, shouldAnimate }) => {
|
backdropClass: ({ fadedIn, shouldAnimate }) => {
|
||||||
|
@ -246,6 +247,13 @@
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this._a11yDialog.hide()
|
this._a11yDialog.hide()
|
||||||
|
},
|
||||||
|
onClickHeader (e) {
|
||||||
|
if (this.get().clickHeaderToClose) {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
this._a11yDialog.hide()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue