Add slideshow widget
This commit is contained in:
		
							parent
							
								
									d1bd9fa552
								
							
						
					
					
						commit
						2112fb3896
					
				
					 3 changed files with 171 additions and 0 deletions
				
			
		|  | @ -995,6 +995,7 @@ _widgets: | ||||||
|   digitalClock: "デジタル時計" |   digitalClock: "デジタル時計" | ||||||
|   federation: "連合" |   federation: "連合" | ||||||
|   postForm: "投稿フォーム" |   postForm: "投稿フォーム" | ||||||
|  |   slideshow: "スライドショー" | ||||||
| 
 | 
 | ||||||
| _cw: | _cw: | ||||||
|   hide: "隠す" |   hide: "隠す" | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ export default function(app: App) { | ||||||
| 	app.component('MkwDigitalClock', defineAsyncComponent(() => import('./digital-clock.vue'))); | 	app.component('MkwDigitalClock', defineAsyncComponent(() => import('./digital-clock.vue'))); | ||||||
| 	app.component('MkwFederation', defineAsyncComponent(() => import('./federation.vue'))); | 	app.component('MkwFederation', defineAsyncComponent(() => import('./federation.vue'))); | ||||||
| 	app.component('MkwPostForm', defineAsyncComponent(() => import('./post-form.vue'))); | 	app.component('MkwPostForm', defineAsyncComponent(() => import('./post-form.vue'))); | ||||||
|  | 	app.component('MkwSlideshow', defineAsyncComponent(() => import('./slideshow.vue'))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const widgets = [ | export const widgets = [ | ||||||
|  | @ -28,4 +29,5 @@ export const widgets = [ | ||||||
| 	'digitalClock', | 	'digitalClock', | ||||||
| 	'federation', | 	'federation', | ||||||
| 	'postForm', | 	'postForm', | ||||||
|  | 	'slideshow', | ||||||
| ]; | ]; | ||||||
|  |  | ||||||
							
								
								
									
										168
									
								
								src/client/widgets/slideshow.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								src/client/widgets/slideshow.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,168 @@ | ||||||
|  | <template> | ||||||
|  | <div class="kvausudm _panel"> | ||||||
|  | 	<div @click="choose"> | ||||||
|  | 		<p v-if="props.folderId == null"> | ||||||
|  | 			<template v-if="isCustomizeMode">{{ $t('folder-customize-mode') }}</template> | ||||||
|  | 			<template v-else>{{ $t('folder') }}</template> | ||||||
|  | 		</p> | ||||||
|  | 		<p v-if="props.folderId != null && images.length === 0 && !fetching">{{ $t('no-image') }}</p> | ||||||
|  | 		<div ref="slideA" class="slide a"></div> | ||||||
|  | 		<div ref="slideB" class="slide b"></div> | ||||||
|  | 	</div> | ||||||
|  | </div> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script lang="ts"> | ||||||
|  | import { defineComponent } from 'vue'; | ||||||
|  | import {  } from '@fortawesome/free-solid-svg-icons'; | ||||||
|  | import define from './define'; | ||||||
|  | import * as os from '@/os'; | ||||||
|  | 
 | ||||||
|  | const widget = define({ | ||||||
|  | 	name: 'slideshow', | ||||||
|  | 	props: () => ({ | ||||||
|  | 		height: { | ||||||
|  | 			type: 'number', | ||||||
|  | 			default: 300, | ||||||
|  | 		}, | ||||||
|  | 		folderId: { | ||||||
|  | 			type: 'string', | ||||||
|  | 			default: null, | ||||||
|  | 			hidden: true, | ||||||
|  | 		}, | ||||||
|  | 	}) | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | export default defineComponent({ | ||||||
|  | 	extends: widget, | ||||||
|  | 	data() { | ||||||
|  | 		return { | ||||||
|  | 			images: [], | ||||||
|  | 			fetching: true, | ||||||
|  | 			clock: null | ||||||
|  | 		}; | ||||||
|  | 	}, | ||||||
|  | 	mounted() { | ||||||
|  | 		this.$nextTick(() => { | ||||||
|  | 			this.applySize(); | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  | 		if (this.props.folderId != null) { | ||||||
|  | 			this.fetch(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		this.clock = setInterval(this.change, 10000); | ||||||
|  | 	}, | ||||||
|  | 	beforeUnmount() { | ||||||
|  | 		clearInterval(this.clock); | ||||||
|  | 	}, | ||||||
|  | 	methods: { | ||||||
|  | 		applySize() { | ||||||
|  | 			let h; | ||||||
|  | 
 | ||||||
|  | 			if (this.props.size == 1) { | ||||||
|  | 				h = 250; | ||||||
|  | 			} else { | ||||||
|  | 				h = 170; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			this.$el.style.height = `${h}px`; | ||||||
|  | 		}, | ||||||
|  | 		resize() { | ||||||
|  | 			if (this.props.size == 1) { | ||||||
|  | 				this.props.size = 0; | ||||||
|  | 			} else { | ||||||
|  | 				this.props.size++; | ||||||
|  | 			} | ||||||
|  | 			this.save(); | ||||||
|  | 
 | ||||||
|  | 			this.applySize(); | ||||||
|  | 		}, | ||||||
|  | 		change() { | ||||||
|  | 			if (this.images.length == 0) return; | ||||||
|  | 
 | ||||||
|  | 			const index = Math.floor(Math.random() * this.images.length); | ||||||
|  | 			const img = `url(${ this.images[index].url })`; | ||||||
|  | 
 | ||||||
|  | 			(this.$refs.slideB as any).style.backgroundImage = img; | ||||||
|  | 
 | ||||||
|  | 			this.$refs.slideB.classList.add('anime'); | ||||||
|  | 			setTimeout(() => { | ||||||
|  | 				// 既にこのウィジェットがunmountされていたら要素がない | ||||||
|  | 				if ((this.$refs.slideA as any) == null) return; | ||||||
|  | 
 | ||||||
|  | 				(this.$refs.slideA as any).style.backgroundImage = img; | ||||||
|  | 
 | ||||||
|  | 				this.$refs.slideB.classList.remove('anime'); | ||||||
|  | 			}, 1000); | ||||||
|  | 		}, | ||||||
|  | 		fetch() { | ||||||
|  | 			this.fetching = true; | ||||||
|  | 
 | ||||||
|  | 			os.api('drive/files', { | ||||||
|  | 				folderId: this.props.folderId, | ||||||
|  | 				type: 'image/*', | ||||||
|  | 				limit: 100 | ||||||
|  | 			}).then(images => { | ||||||
|  | 				this.images = images; | ||||||
|  | 				this.fetching = false; | ||||||
|  | 				(this.$refs.slideA as any).style.backgroundImage = ''; | ||||||
|  | 				(this.$refs.slideB as any).style.backgroundImage = ''; | ||||||
|  | 				this.change(); | ||||||
|  | 			}); | ||||||
|  | 		}, | ||||||
|  | 		choose() { | ||||||
|  | 			os.selectDriveFolder(false).then(folder => { | ||||||
|  | 				if (folder == null) { | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  | 				this.props.folderId = folder.id; | ||||||
|  | 				this.save(); | ||||||
|  | 				this.fetch(); | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .kvausudm { | ||||||
|  | 	position: relative; | ||||||
|  | 
 | ||||||
|  | 	> div { | ||||||
|  | 		width: 100%; | ||||||
|  | 		height: 100%; | ||||||
|  | 		cursor: pointer; | ||||||
|  | 
 | ||||||
|  | 		> p { | ||||||
|  | 			display: block; | ||||||
|  | 			margin: 1em; | ||||||
|  | 			text-align: center; | ||||||
|  | 			color: #888; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		> * { | ||||||
|  | 			pointer-events: none; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		> .slide { | ||||||
|  | 			position: absolute; | ||||||
|  | 			top: 0; | ||||||
|  | 			left: 0; | ||||||
|  | 			width: 100%; | ||||||
|  | 			height: 100%; | ||||||
|  | 			background-size: cover; | ||||||
|  | 			background-position: center; | ||||||
|  | 
 | ||||||
|  | 			&.b { | ||||||
|  | 				opacity: 0; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			&.anime { | ||||||
|  | 				transition: opacity 1s; | ||||||
|  | 				opacity: 1; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | </style> | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue