feat: add pinch-zoom to media dialog (#933)

* feat: add pinch-zoom to media dialog

* fix zoom buttons
This commit is contained in:
Nolan Lawson 2019-02-03 12:33:15 -08:00 committed by GitHub
parent 4c430bd1c9
commit 6d2b3ec072
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 213 additions and 38 deletions

1
.gitignore vendored
View File

@ -9,3 +9,4 @@ node_modules
/static/inline-script.js.map /static/inline-script.js.map
/static/emoji-mart-all.json /static/emoji-mart-all.json
/src/inline-script/checksum.js /src/inline-script/checksum.js
yarn-error.log

View File

@ -40,6 +40,7 @@ module.exports = [
{ id: 'fa-circle', src: 'src/thirdparty/font-awesome-svg-png/white/svg/circle.svg' }, { id: 'fa-circle', src: 'src/thirdparty/font-awesome-svg-png/white/svg/circle.svg' },
{ id: 'fa-circle-o', src: 'src/thirdparty/font-awesome-svg-png/white/svg/circle-o.svg' }, { id: 'fa-circle-o', src: 'src/thirdparty/font-awesome-svg-png/white/svg/circle-o.svg' },
{ id: 'fa-angle-left', src: 'src/thirdparty/font-awesome-svg-png/white/svg/angle-left.svg' }, { id: 'fa-angle-left', src: 'src/thirdparty/font-awesome-svg-png/white/svg/angle-left.svg' },
{ id: 'fa-angle-right', src: 'src/thirdparty/font-awesome-svg-png/white/svg/angle-right.svg' } { id: 'fa-angle-right', src: 'src/thirdparty/font-awesome-svg-png/white/svg/angle-right.svg' },
{ id: 'fa-search-minus', src: 'src/thirdparty/font-awesome-svg-png/white/svg/search-minus.svg' },
{ id: 'fa-search-plus', src: 'src/thirdparty/font-awesome-svg-png/white/svg/search-plus.svg' }
] ]

View File

@ -78,6 +78,7 @@
"p-any": "^1.1.0", "p-any": "^1.1.0",
"page-lifecycle": "^0.1.1", "page-lifecycle": "^0.1.1",
"performance-now": "^2.1.0", "performance-now": "^2.1.0",
"pinch-zoom-element": "^1.1.0",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"quick-lru": "^2.0.0", "quick-lru": "^2.0.0",
"remount": "^0.9.3", "remount": "^0.9.3",

View File

@ -11,44 +11,58 @@
<div class="media-scroll-item"> <div 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-inner-inner">
<MediaInDialog {media} /> <PinchZoomable className='media-pinch-zoom' disabled={!pinchZoomMode} >
<MediaInDialog {media} />
</PinchZoomable>
</div> </div>
</div> </div>
</div> </div>
{/each} {/each}
</div> </div>
{#if dots.length > 1} <div class="media-controls-outside">
<div class="media-controls"> <IconButton
<IconButton className="media-control-button media-control-button-dummy-spacer"
className="media-control-button" href="#fa-search"
disabled={scrolledItem === 0} />
label="Show previous media" {#if dots.length > 1}
href="#fa-angle-left" <div class="media-controls">
on:click="prev()" <IconButton
/> className="media-control-button"
{#each dots as dot, i (dot.i)} disabled={scrolledItem === 0}
<IconButton label="Show previous media"
className="media-control-button" href="#fa-angle-left"
pressable={true} on:click="prev()"
label="Show {nth(i)} media" />
pressed={i === scrolledItem} {#each dots as dot, i (dot.i)}
href={i === scrolledItem ? '#fa-circle' : '#fa-circle-o'} <IconButton
sameColorWhenPressed={true} className="media-control-button"
on:click="onClick(i)" pressable={true}
/> label="Show {nth(i)} media"
{/each} pressed={i === scrolledItem}
<IconButton href={i === scrolledItem ? '#fa-circle' : '#fa-circle-o'}
className="media-control-button" sameColorWhenPressed={true}
disabled={scrolledItem === length - 1} on:click="onClick(i)"
label="Show next media" />
href="#fa-angle-right" {/each}
on:click="next()" <IconButton
/> className="media-control-button"
</div> disabled={scrolledItem === length - 1}
{/if} label="Show next media"
href="#fa-angle-right"
on:click="next()"
/>
</div>
{/if}
<IconButton
className="media-control-button"
pressable={true}
pressed={pinchZoomMode}
label={pinchZoomMode ? 'Disable pinch-zoom mode' : 'Enable pinch-zoom mode'}
href="#fa-search"
on:click="togglePinchZoomMode()"
/>
</div>
</div> </div>
</ModalDialog> </ModalDialog>
<Shortcut scope='mediaDialog' key="ArrowLeft" on:pressed="prev()" /> <Shortcut scope='mediaDialog' key="ArrowLeft" on:pressed="prev()" />
@ -92,14 +106,37 @@
padding: 5px; padding: 5px;
} }
.media-controls-outside {
display: flex;
justify-content: space-between;
margin: 10px;
}
.media-controls { .media-controls {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
margin: 10px auto;
} }
:global(.media-control-button) { :global(.media-pinch-zoom) {
margin: 0 5px; width: 100%;
height: 100%;
}
:global(.media-control-button-dummy-spacer) {
visibility: hidden;
}
@media (min-width: 768px) {
:global(.media-control-button) {
margin: 0 5px;
}
}
@media (max-width: 320px) {
:global(.icon-button.media-control-button) {
padding-left: 5px;
padding-right: 5px;
}
} }
@supports (scroll-snap-align: start) { @supports (scroll-snap-align: start) {
@ -129,6 +166,7 @@
import MediaInDialog from './MediaInDialog.html' import MediaInDialog from './MediaInDialog.html'
import IconButton from '../../IconButton.html' import IconButton from '../../IconButton.html'
import Shortcut from '../../shortcut/Shortcut.html' import Shortcut from '../../shortcut/Shortcut.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 debounce from 'lodash-es/debounce' import debounce from 'lodash-es/debounce'
@ -163,6 +201,9 @@
popShortcutScope('mediaDialog') popShortcutScope('mediaDialog')
}, },
store: () => store, store: () => store,
data: () => ({
pinchZoomMode: false
}),
computed: { computed: {
length: ({ mediaItems }) => mediaItems.length, length: ({ mediaItems }) => mediaItems.length,
dots: ({ length }) => times(length, i => ({ i })) dots: ({ length }) => times(length, i => ({ i }))
@ -171,7 +212,8 @@
ModalDialog, ModalDialog,
MediaInDialog, MediaInDialog,
IconButton, IconButton,
Shortcut Shortcut,
PinchZoomable
}, },
helpers: { helpers: {
nth (i) { nth (i) {
@ -229,6 +271,9 @@
} else { } else {
scroller.scrollLeft = scrollLeft scroller.scrollLeft = scrollLeft
} }
},
togglePinchZoomMode () {
this.set({ pinchZoomMode: !this.get().pinchZoomMode })
} }
} }
} }

View File

@ -0,0 +1,115 @@
<div class="pinch-zoom {disabled ? 'pinch-zoom-disabled' : ''} {className ? className : ''}" >
<pinch-zoom class="pinch-zoom-inner" ref:node>
<slot></slot>
</pinch-zoom>
<IconButton
className="pinch-zoom-button pinch-zoom-button-zoom-out"
muted={true}
label="Zoom out"
href="#fa-search-minus"
on:click="zoomOut()"
/>
<IconButton
className="pinch-zoom-button pinch-zoom-button-zoom-in"
muted={true}
label="Zoom in"
href="#fa-search-plus"
on:click="zoomIn()"
/>
</div>
<style>
.pinch-zoom {
position: relative;
}
.pinch-zoom-disabled {
pointer-events: none;
}
.pinch-zoom-inner {
width: 100%;
height: 100%;
}
:global(.icon-button.pinch-zoom-button) {
position: absolute;
z-index: 110;
bottom: 10px;
background: var(--mask-opaque-bg);
}
:global(.pinch-zoom-button-zoom-in) {
right: 10px;
}
:global(.pinch-zoom-button-zoom-out) {
left: 10px;
}
@media (max-width: 767px) {
:global(.pinch-zoom-button-zoom-in) {
right: 5px;
}
:global(.pinch-zoom-button-zoom-out) {
left: 5px;
}
}
@media (max-width: 320px) {
:global(.icon-button.pinch-zoom-button) {
padding-left: 5px;
padding-right: 5px;
}
}
:global(.pinch-zoom-disabled .pinch-zoom-button) {
visibility: hidden;
}
</style>
<script>
import IconButton from '../../IconButton.html'
import 'pinch-zoom-element/dist/pinch-zoom.js'
import { observe } from 'svelte-extras'
const ZOOM_INCREMENT = 0.1
export default {
oncreate () {
this.observe('disabled', disabled => {
if (disabled) {
this.resetZoom()
}
}, { init: false })
},
data: () => ({
disabled: false
}),
components: {
IconButton
},
methods: {
observe,
zoomIn () {
this.zoomBy(ZOOM_INCREMENT)
},
zoomOut () {
this.zoomBy(-ZOOM_INCREMENT)
},
zoomBy (increment) {
let { node } = this.refs
let scale = node.scale || 1
node.scaleTo(scale + increment, {
originX: '50%',
originY: '50%'
})
},
resetZoom () {
let { node } = this.refs
node.setTransform({
scale: 1,
x: 0,
y: 0
})
}
}
}
</script>

View File

@ -5604,6 +5604,13 @@ pify@^3.0.0:
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
pinch-zoom-element@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/pinch-zoom-element/-/pinch-zoom-element-1.1.0.tgz#0e12c3f7bd63631e45596d1417a15759f80a4e9c"
integrity sha512-jzF7Uad61b1+BnaEktbtOl025WaLDbwVgpcG4qive1OLwuFNU2Itt2c5tD6pp1sx4XgKhLzqjVgQ9qmCr3y6Ew==
dependencies:
pointer-tracker "^2.0.3"
pinkie-promise@^1.0.0: pinkie-promise@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-1.0.0.tgz#d1da67f5482563bb7cf57f286ae2822ecfbf3670" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-1.0.0.tgz#d1da67f5482563bb7cf57f286ae2822ecfbf3670"
@ -5685,6 +5692,11 @@ pngjs@^3.3.1:
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.3.3.tgz#85173703bde3edac8998757b96e5821d0966a21b" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.3.3.tgz#85173703bde3edac8998757b96e5821d0966a21b"
integrity sha512-1n3Z4p3IOxArEs1VRXnZ/RXdfEniAUS9jb68g58FIXMNkPJeZd+Qh4Uq7/e0LVxAQGos1eIUrqrt4FpjdnEd+Q== integrity sha512-1n3Z4p3IOxArEs1VRXnZ/RXdfEniAUS9jb68g58FIXMNkPJeZd+Qh4Uq7/e0LVxAQGos1eIUrqrt4FpjdnEd+Q==
pointer-tracker@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/pointer-tracker/-/pointer-tracker-2.0.3.tgz#6e66be8330e9f4e83c81d76e1d78e42eb4f89c00"
integrity sha512-PURBF4oc45JPECuguX6oPL3pJU5AlF0Nb/4sZdmqzPNAkV4LGL9MJMqb0smWDtmQ0F0KpbxEJn4/Lf5ugN1keQ==
posix-character-classes@^0.1.0: posix-character-classes@^0.1.0:
version "0.1.1" version "0.1.1"
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"