forked from cybrespace/pinafore
		
	feat: add pinch-zoom to media dialog (#933)
* feat: add pinch-zoom to media dialog * fix zoom buttons
This commit is contained in:
		
							parent
							
								
									4c430bd1c9
								
							
						
					
					
						commit
						6d2b3ec072
					
				
					 6 changed files with 213 additions and 38 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -9,3 +9,4 @@ node_modules | |||
| /static/inline-script.js.map | ||||
| /static/emoji-mart-all.json | ||||
| /src/inline-script/checksum.js | ||||
| yarn-error.log | ||||
|  |  | |||
|  | @ -40,6 +40,7 @@ module.exports = [ | |||
|   { 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-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' } | ||||
| ] | ||||
|  |  | |||
|  | @ -78,6 +78,7 @@ | |||
|     "p-any": "^1.1.0", | ||||
|     "page-lifecycle": "^0.1.1", | ||||
|     "performance-now": "^2.1.0", | ||||
|     "pinch-zoom-element": "^1.1.0", | ||||
|     "prop-types": "^15.6.2", | ||||
|     "quick-lru": "^2.0.0", | ||||
|     "remount": "^0.9.3", | ||||
|  |  | |||
|  | @ -11,12 +11,19 @@ | |||
|         <div class="media-scroll-item"> | ||||
|           <div class="media-scroll-item-inner"> | ||||
|             <div class="media-scroll-item-inner-inner"> | ||||
|                 <PinchZoomable className='media-pinch-zoom' disabled={!pinchZoomMode} > | ||||
|                   <MediaInDialog {media} /> | ||||
|                 </PinchZoomable> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       {/each} | ||||
|     </div> | ||||
|     <div class="media-controls-outside"> | ||||
|       <IconButton | ||||
|         className="media-control-button media-control-button-dummy-spacer" | ||||
|         href="#fa-search" | ||||
|       /> | ||||
|       {#if dots.length > 1} | ||||
|         <div class="media-controls"> | ||||
|             <IconButton | ||||
|  | @ -46,9 +53,16 @@ | |||
|             /> | ||||
|         </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> | ||||
| 
 | ||||
| 
 | ||||
| </ModalDialog> | ||||
| 
 | ||||
| <Shortcut scope='mediaDialog' key="ArrowLeft" on:pressed="prev()" /> | ||||
|  | @ -92,15 +106,38 @@ | |||
|     padding: 5px; | ||||
|   } | ||||
| 
 | ||||
|   .media-controls-outside { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     margin: 10px; | ||||
|   } | ||||
| 
 | ||||
|   .media-controls { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     margin: 10px auto; | ||||
|   } | ||||
| 
 | ||||
|   :global(.media-pinch-zoom) { | ||||
|     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) { | ||||
|     /* modern scroll snap points */ | ||||
|  | @ -129,6 +166,7 @@ | |||
|   import MediaInDialog from './MediaInDialog.html' | ||||
|   import IconButton from '../../IconButton.html' | ||||
|   import Shortcut from '../../shortcut/Shortcut.html' | ||||
|   import PinchZoomable from './PinchZoomable.html' | ||||
|   import { show } from '../helpers/showDialog' | ||||
|   import { oncreate as onCreateDialog } from '../helpers/onCreateDialog' | ||||
|   import debounce from 'lodash-es/debounce' | ||||
|  | @ -163,6 +201,9 @@ | |||
|       popShortcutScope('mediaDialog') | ||||
|     }, | ||||
|     store: () => store, | ||||
|     data: () => ({ | ||||
|       pinchZoomMode: false | ||||
|     }), | ||||
|     computed: { | ||||
|       length: ({ mediaItems }) => mediaItems.length, | ||||
|       dots: ({ length }) => times(length, i => ({ i })) | ||||
|  | @ -171,7 +212,8 @@ | |||
|       ModalDialog, | ||||
|       MediaInDialog, | ||||
|       IconButton, | ||||
|       Shortcut | ||||
|       Shortcut, | ||||
|       PinchZoomable | ||||
|     }, | ||||
|     helpers: { | ||||
|       nth (i) { | ||||
|  | @ -229,6 +271,9 @@ | |||
|         } else { | ||||
|           scroller.scrollLeft = scrollLeft | ||||
|         } | ||||
|       }, | ||||
|       togglePinchZoomMode () { | ||||
|         this.set({ pinchZoomMode: !this.get().pinchZoomMode }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  |  | |||
							
								
								
									
										115
									
								
								src/routes/_components/dialog/components/PinchZoomable.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								src/routes/_components/dialog/components/PinchZoomable.html
									
										
									
									
									
										Normal 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> | ||||
							
								
								
									
										12
									
								
								yarn.lock
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								yarn.lock
									
										
									
									
									
								
							|  | @ -5604,6 +5604,13 @@ pify@^3.0.0: | |||
|   resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" | ||||
|   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: | ||||
|   version "1.0.0" | ||||
|   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" | ||||
|   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: | ||||
|   version "0.1.1" | ||||
|   resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue