feat(client): Improve image viewer
Resolve #7545 Resolve #6811 Close #7808
This commit is contained in:
		
							parent
							
								
									67bf6ff3ce
								
							
						
					
					
						commit
						e52a9e0a65
					
				
					 5 changed files with 67 additions and 62 deletions
				
			
		|  | @ -10,11 +10,16 @@ | |||
| ## 12.x.x (unreleased) | ||||
| 
 | ||||
| ### Improvements | ||||
| - クライアント: 画像ビューアを強化 | ||||
| - クライアント: メンションにユーザーのアバターを表示するように | ||||
| - クライアント: デザインの調整 | ||||
| - クライアント: twemojiをセルフホスティングするように | ||||
| 
 | ||||
| ### Bugfixes | ||||
| - クライアント: CWで画像が隠されたとき、画像の高さがおかしいことになる問題を修正 | ||||
| 
 | ||||
| ### NOTE | ||||
| - このバージョンから、iOS 15未満のサポートがされなくなります。対象のバージョンをお使いの方は、iOSのバージョンアップを行ってください。 | ||||
| 
 | ||||
| ## 12.93.2 (2021/10/23) | ||||
| 
 | ||||
|  |  | |||
|  | @ -183,6 +183,7 @@ | |||
| 		"os-utils": "0.0.14", | ||||
| 		"parse5": "6.0.1", | ||||
| 		"pg": "8.7.1", | ||||
| 		"photoswipe": "git://github.com/dimsemenov/photoswipe#v5-beta", | ||||
| 		"portscanner": "2.2.0", | ||||
| 		"postcss": "8.3.11", | ||||
| 		"postcss-loader": "6.2.0", | ||||
|  |  | |||
|  | @ -12,7 +12,6 @@ | |||
| 	<a | ||||
| 		:href="image.url" | ||||
| 		:title="image.name" | ||||
| 		@click.prevent="onClick" | ||||
| 	> | ||||
| 		<ImgWithBlurhash :hash="image.blurhash" :src="url" :alt="image.comment" :title="image.comment" :cover="false"/> | ||||
| 		<div class="gif" v-if="image.type === 'image/gif'">GIF</div> | ||||
|  | @ -73,17 +72,6 @@ export default defineComponent({ | |||
| 			immediate: true, | ||||
| 		}); | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		onClick() { | ||||
| 			if (this.$store.state.imageNewTab) { | ||||
| 				window.open(this.image.url, '_blank'); | ||||
| 			} else { | ||||
| 				os.popup(ImageViewer, { | ||||
| 					image: this.image | ||||
| 				}, {}, 'closed'); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,11 +1,11 @@ | |||
| <template> | ||||
| <div class="mk-media-list"> | ||||
| <div class="hoawjimk"> | ||||
| 	<XBanner v-for="media in mediaList.filter(media => !previewable(media))" :media="media" :key="media.id"/> | ||||
| 	<div v-if="mediaList.filter(media => previewable(media)).length > 0" class="gird-container" ref="gridOuter"> | ||||
| 		<div :data-count="mediaList.filter(media => previewable(media)).length" :style="gridInnerStyle"> | ||||
| 	<div v-if="mediaList.filter(media => previewable(media)).length > 0" class="gird-container"> | ||||
| 		<div :data-count="mediaList.filter(media => previewable(media)).length" ref="gallery"> | ||||
| 			<template v-for="media in mediaList"> | ||||
| 				<XVideo :video="media" :key="media.id" v-if="media.type.startsWith('video')"/> | ||||
| 				<XImage :image="media" :key="media.id" v-else-if="media.type.startsWith('image')" :raw="raw"/> | ||||
| 				<XImage class="image" :data-id="media.id" :image="media" :key="media.id" v-else-if="media.type.startsWith('image')" :raw="raw"/> | ||||
| 			</template> | ||||
| 		</div> | ||||
| 	</div> | ||||
|  | @ -13,11 +13,16 @@ | |||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import { defineComponent } from 'vue'; | ||||
| import { defineComponent, onMounted, PropType, ref } from 'vue'; | ||||
| import * as misskey from 'misskey-js'; | ||||
| import PhotoSwipeLightbox from 'photoswipe/dist/photoswipe-lightbox.esm.js'; | ||||
| import PhotoSwipe from 'photoswipe/dist/photoswipe.esm.js'; | ||||
| import 'photoswipe/dist/photoswipe.css'; | ||||
| import XBanner from './media-banner.vue'; | ||||
| import XImage from './media-image.vue'; | ||||
| import XVideo from './media-video.vue'; | ||||
| import * as os from '@client/os'; | ||||
| import { defaultStore } from '@client/store'; | ||||
| 
 | ||||
| export default defineComponent({ | ||||
| 	components: { | ||||
|  | @ -27,63 +32,65 @@ export default defineComponent({ | |||
| 	}, | ||||
| 	props: { | ||||
| 		mediaList: { | ||||
| 			required: true | ||||
| 			type: Array as PropType<misskey.entities.DriveFile[]>, | ||||
| 			required: true, | ||||
| 		}, | ||||
| 		raw: { | ||||
| 			default: false | ||||
| 		}, | ||||
| 	}, | ||||
| 	data() { | ||||
| 		return { | ||||
| 			gridInnerStyle: {}, | ||||
| 			sizeWaiting: false | ||||
| 		} | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		this.size(); | ||||
| 		window.addEventListener('resize', this.size); | ||||
| 	}, | ||||
| 	beforeUnmount() { | ||||
| 		window.removeEventListener('resize', this.size); | ||||
| 	}, | ||||
| 	activated() { | ||||
| 		this.size(); | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		previewable(file) { | ||||
| 			return file.type.startsWith('video') || file.type.startsWith('image'); | ||||
| 		}, | ||||
| 		size() { | ||||
| 			// for Safari bug | ||||
| 			if (this.sizeWaiting) return; | ||||
| 	setup(props) { | ||||
| 		const gallery = ref(null); | ||||
| 
 | ||||
| 			this.sizeWaiting = true; | ||||
| 
 | ||||
| 			window.requestAnimationFrame(() => { | ||||
| 				this.sizeWaiting = false; | ||||
| 
 | ||||
| 				if (this.$refs.gridOuter) { | ||||
| 					let height = 287; | ||||
| 					const parent = this.$parent.$el; | ||||
| 
 | ||||
| 					if (this.$refs.gridOuter.clientHeight) { | ||||
| 						height = this.$refs.gridOuter.clientHeight; | ||||
| 					} else if (parent) { | ||||
| 						height = parent.getBoundingClientRect().width * 9 / 16; | ||||
| 					} | ||||
| 
 | ||||
| 					this.gridInnerStyle = { height: `${height}px` }; | ||||
| 				} else { | ||||
| 					this.gridInnerStyle = {}; | ||||
| 				} | ||||
| 		onMounted(() => { | ||||
| 			const lightbox = new PhotoSwipeLightbox({ | ||||
| 				dataSource: props.mediaList.filter(media => media.type.startsWith('image')).map(media => ({ | ||||
| 					src: media.url, | ||||
| 					w: media.properties.width, | ||||
| 					h: media.properties.height, | ||||
| 					alt: media.name, | ||||
| 				})), | ||||
| 				gallery: gallery.value, | ||||
| 				children: '.image', | ||||
| 				thumbSelector: '.image', | ||||
| 				pswpModule: PhotoSwipe | ||||
| 			}); | ||||
| 		} | ||||
| 
 | ||||
| 			lightbox.on('itemData', (e) => { | ||||
| 				const { itemData } = e; | ||||
| 
 | ||||
| 				// element is children | ||||
| 				const { element } = itemData; | ||||
| 
 | ||||
| 				console.log(element); | ||||
| 
 | ||||
| 				const id = element.dataset.id; | ||||
| 				const file = props.mediaList.find(media => media.id === id); | ||||
| 
 | ||||
| 				itemData.src = file.url; | ||||
| 				itemData.w = Number(file.properties.width); | ||||
| 				itemData.h = Number(file.properties.height); | ||||
| 				itemData.msrc = file.thumbnailUrl; | ||||
| 				itemData.thumbCropped = true; | ||||
| 			}); | ||||
| 
 | ||||
| 			lightbox.init(); | ||||
| 		}); | ||||
| 
 | ||||
| 		const previewable = (file: misskey.entities.DriveFile): boolean => { | ||||
| 			return file.type.startsWith('video') || file.type.startsWith('image'); | ||||
| 		}; | ||||
| 
 | ||||
| 		return { | ||||
| 			previewable, | ||||
| 			gallery, | ||||
| 		}; | ||||
| 	}, | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .mk-media-list { | ||||
| .hoawjimk { | ||||
| 	> .gird-container { | ||||
| 		position: relative; | ||||
| 		width: 100%; | ||||
|  |  | |||
|  | @ -8271,6 +8271,10 @@ pgpass@1.x: | |||
|   dependencies: | ||||
|     split "^1.0.0" | ||||
| 
 | ||||
| "photoswipe@git://github.com/dimsemenov/photoswipe#v5-beta": | ||||
|   version "5.1.7" | ||||
|   resolved "git://github.com/dimsemenov/photoswipe#60040164333bd257409669e715e4327afdb3aec7" | ||||
| 
 | ||||
| picocolors@^1.0.0: | ||||
|   version "1.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue