aboutsummaryrefslogtreecommitdiff
path: root/src/components/media_modal/media_modal.vue
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/media_modal/media_modal.vue')
-rw-r--r--src/components/media_modal/media_modal.vue271
1 files changed, 211 insertions, 60 deletions
diff --git a/src/components/media_modal/media_modal.vue b/src/components/media_modal/media_modal.vue
index 54bc5335..d59055b3 100644
--- a/src/components/media_modal/media_modal.vue
+++ b/src/components/media_modal/media_modal.vue
@@ -2,18 +2,38 @@
<Modal
v-if="showing"
class="media-modal-view"
- @backdropClicked="hide"
+ @backdropClicked="hideIfNotSwiped"
>
- <img
+ <SwipeClick
v-if="type === 'image'"
- class="modal-image"
- :src="currentMedia.url"
- :alt="currentMedia.description"
- :title="currentMedia.description"
- @touchstart.stop="mediaTouchStart"
- @touchmove.stop="mediaTouchMove"
- @click="hide"
+ ref="swipeClick"
+ class="modal-image-container"
+ :direction="swipeDirection"
+ :threshold="swipeThreshold"
+ @preview-requested="handleSwipePreview"
+ @swipe-finished="handleSwipeEnd"
+ @swipeless-clicked="hide"
>
+ <PinchZoom
+ ref="pinchZoom"
+ class="modal-image-container-inner"
+ selector=".modal-image"
+ reach-min-scale-strategy="reset"
+ stop-propagate-handled="stop-propgate-handled"
+ :allow-pan-min-scale="pinchZoomMinScale"
+ :min-scale="pinchZoomMinScale"
+ :reset-to-min-scale-limit="pinchZoomScaleResetLimit"
+ >
+ <img
+ :class="{ loading }"
+ class="modal-image"
+ :src="currentMedia.url"
+ :alt="currentMedia.description"
+ :title="currentMedia.description"
+ @load="onImageLoaded"
+ >
+ </PinchZoom>
+ </SwipeClick>
<VideoAttachment
v-if="type === 'video'"
class="modal-image"
@@ -28,38 +48,84 @@
:title="currentMedia.description"
controls
/>
+ <Flash
+ v-if="type === 'flash'"
+ class="modal-image"
+ :src="currentMedia.url"
+ :alt="currentMedia.description"
+ :title="currentMedia.description"
+ />
<button
v-if="canNavigate"
:title="$t('media_modal.previous')"
- class="modal-view-button-arrow modal-view-button-arrow--prev"
+ class="modal-view-button modal-view-button-arrow modal-view-button-arrow--prev"
@click.stop.prevent="goPrev"
>
<FAIcon
- class="arrow-icon"
+ class="button-icon arrow-icon"
icon="chevron-left"
/>
</button>
<button
v-if="canNavigate"
:title="$t('media_modal.next')"
- class="modal-view-button-arrow modal-view-button-arrow--next"
+ class="modal-view-button modal-view-button-arrow modal-view-button-arrow--next"
@click.stop.prevent="goNext"
>
<FAIcon
- class="arrow-icon"
+ class="button-icon arrow-icon"
icon="chevron-right"
/>
</button>
+ <button
+ class="modal-view-button modal-view-button-hide"
+ :title="$t('media_modal.hide')"
+ @click.stop.prevent="hide"
+ >
+ <FAIcon
+ class="button-icon"
+ icon="times"
+ />
+ </button>
+
+ <span
+ v-if="description"
+ class="description"
+ >
+ {{ description }}
+ </span>
+ <span
+ class="counter"
+ >
+ {{ $tc('media_modal.counter', currentIndex + 1, { current: currentIndex + 1, total: media.length }) }}
+ </span>
+ <span
+ v-if="loading"
+ class="loading-spinner"
+ >
+ <FAIcon
+ spin
+ icon="circle-notch"
+ size="5x"
+ />
+ </span>
</Modal>
</template>
<script src="./media_modal.js"></script>
<style lang="scss">
+$modal-view-button-icon-height: 3em;
+$modal-view-button-icon-half-height: calc(#{$modal-view-button-icon-height} / 2);
+$modal-view-button-icon-width: 3em;
+$modal-view-button-icon-margin: 0.5em;
+
.modal-view.media-modal-view {
- z-index: 1001;
+ z-index: var(--ZI_media_modal);
+ flex-direction: column;
- .modal-view-button-arrow {
+ .modal-view-button-arrow,
+ .modal-view-button-hide {
opacity: 0.75;
&:focus,
@@ -67,69 +133,154 @@
outline: none;
box-shadow: none;
}
+
&:hover {
opacity: 1;
}
}
+ overflow: hidden;
}
-@keyframes media-fadein {
- from {
- opacity: 0;
+.media-modal-view {
+ @keyframes media-fadein {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
}
- to {
- opacity: 1;
+
+ .modal-image-container {
+ display: flex;
+ overflow: hidden;
+ align-items: center;
+ flex-direction: column;
+ max-width: 100%;
+ max-height: 100%;
+ width: 100%;
+ height: 100%;
+ flex-grow: 1;
+ justify-content: center;
+
+ &-inner {
+ width: 100%;
+ height: 100%;
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ }
}
-}
-.modal-image {
- max-width: 90%;
- max-height: 90%;
- box-shadow: 0px 5px 15px 0 rgba(0, 0, 0, 0.5);
- image-orientation: from-image; // NOTE: only FF supports this
- animation: 0.1s cubic-bezier(0.7, 0, 1, 0.6) media-fadein;
-}
+ .description,
+ .counter {
+ /* Hardcoded since background is also hardcoded */
+ color: white;
+ margin-top: 1em;
+ text-shadow: 0 0 10px black, 0 0 10px black;
+ padding: 0.2em 2em;
+ }
+
+ .description {
+ flex: 0 0 auto;
+ overflow-y: auto;
+ min-height: 1em;
+ max-width: 500px;
+ max-height: 9.5em;
+ word-break: break-all;
+ }
-.modal-view-button-arrow {
- position: absolute;
- display: block;
- top: 50%;
- margin-top: -50px;
- width: 70px;
- height: 100px;
- border: 0;
- padding: 0;
- opacity: 0;
- box-shadow: none;
- background: none;
- appearance: none;
- overflow: visible;
- cursor: pointer;
- transition: opacity 333ms cubic-bezier(.4,0,.22,1);
-
- .arrow-icon {
+ .modal-image {
+ max-width: 100%;
+ max-height: 100%;
+ image-orientation: from-image; // NOTE: only FF supports this
+ animation: 0.1s cubic-bezier(0.7, 0, 1, 0.6) media-fadein;
+
+ &.loading {
+ opacity: 0.5;
+ }
+ }
+
+ .loading-spinner {
+ width: 100%;
+ height: 100%;
position: absolute;
- top: 35px;
- height: 30px;
- width: 32px;
- font-size: 14px;
- line-height: 30px;
- color: #FFF;
- text-align: center;
- background-color: rgba(0,0,0,.3);
+ pointer-events: none;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ svg {
+ color: white;
+ }
}
- &--prev {
- left: 0;
+ .modal-view-button {
+ border: 0;
+ padding: 0;
+ opacity: 0;
+ box-shadow: none;
+ background: none;
+ appearance: none;
+ overflow: visible;
+ cursor: pointer;
+ transition: opacity 333ms cubic-bezier(.4,0,.22,1);
+ height: $modal-view-button-icon-height;
+ width: $modal-view-button-icon-width;
+
+ .button-icon {
+ position: absolute;
+ height: $modal-view-button-icon-height;
+ width: $modal-view-button-icon-width;
+ font-size: 1rem;
+ line-height: $modal-view-button-icon-height;
+ color: #FFF;
+ text-align: center;
+ background-color: rgba(0,0,0,.3);
+ }
+ }
+
+ .modal-view-button-arrow {
+ position: absolute;
+ display: block;
+ top: 50%;
+ margin-top: $modal-view-button-icon-half-height;
+ width: $modal-view-button-icon-width;
+ height: $modal-view-button-icon-height;
+
.arrow-icon {
- left: 6px;
+ position: absolute;
+ top: 0;
+ line-height: $modal-view-button-icon-height;
+ color: #FFF;
+ text-align: center;
+ background-color: rgba(0,0,0,.3);
+ }
+
+ &--prev {
+ left: 0;
+ .arrow-icon {
+ left: $modal-view-button-icon-margin;
+ }
+ }
+
+ &--next {
+ right: 0;
+ .arrow-icon {
+ right: $modal-view-button-icon-margin;
+ }
}
}
- &--next {
+ .modal-view-button-hide {
+ position: absolute;
+ top: 0;
right: 0;
- .arrow-icon {
- right: 6px;
+ .button-icon {
+ top: $modal-view-button-icon-margin;
+ right: $modal-view-button-icon-margin;
}
}
}