enhance(client): アップデート時にも花火
This commit is contained in:
		
							parent
							
								
									82c4f694a0
								
							
						
					
					
						commit
						3b617fafdd
					
				
					 3 changed files with 33 additions and 26 deletions
				
			
		|  | @ -10,12 +10,13 @@ | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
| import { shallowRef } from 'vue'; | import { onMounted, shallowRef } from 'vue'; | ||||||
| import MkModal from '@/components/MkModal.vue'; | import MkModal from '@/components/MkModal.vue'; | ||||||
| import MkButton from '@/components/MkButton.vue'; | import MkButton from '@/components/MkButton.vue'; | ||||||
| import MkSparkle from '@/components/MkSparkle.vue'; | import MkSparkle from '@/components/MkSparkle.vue'; | ||||||
| import { version } from '@/config'; | import { version } from '@/config'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
|  | import { confetti } from '@/scripts/confetti'; | ||||||
| 
 | 
 | ||||||
| const modal = shallowRef<InstanceType<typeof MkModal>>(); | const modal = shallowRef<InstanceType<typeof MkModal>>(); | ||||||
| 
 | 
 | ||||||
|  | @ -23,6 +24,10 @@ const whatIsNew = () => { | ||||||
| 	modal.value.close(); | 	modal.value.close(); | ||||||
| 	window.open(`https://misskey-hub.net/docs/releases.html#_${version.replace(/\./g, '-')}`, '_blank'); | 	window.open(`https://misskey-hub.net/docs/releases.html#_${version.replace(/\./g, '-')}`, '_blank'); | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | onMounted(() => { | ||||||
|  | 	confetti(); | ||||||
|  | }); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
|  |  | ||||||
|  | @ -110,7 +110,6 @@ | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
| import { defineAsyncComponent, computed, inject, onMounted, onUnmounted, watch } from 'vue'; | import { defineAsyncComponent, computed, inject, onMounted, onUnmounted, watch } from 'vue'; | ||||||
| import calcAge from 's-age'; | import calcAge from 's-age'; | ||||||
| import confetti from 'canvas-confetti'; |  | ||||||
| import * as misskey from 'misskey-js'; | import * as misskey from 'misskey-js'; | ||||||
| import XUserTimeline from './index.timeline.vue'; | import XUserTimeline from './index.timeline.vue'; | ||||||
| import XNote from '@/components/MkNote.vue'; | import XNote from '@/components/MkNote.vue'; | ||||||
|  | @ -129,6 +128,7 @@ import { useRouter } from '@/router'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| import { $i } from '@/account'; | import { $i } from '@/account'; | ||||||
| import { dateString } from '@/filters/date'; | import { dateString } from '@/filters/date'; | ||||||
|  | import { confetti } from '@/scripts/confetti'; | ||||||
| 
 | 
 | ||||||
| const XPhotos = defineAsyncComponent(() => import('./index.photos.vue')); | const XPhotos = defineAsyncComponent(() => import('./index.photos.vue')); | ||||||
| const XActivity = defineAsyncComponent(() => import('./index.activity.vue')); | const XActivity = defineAsyncComponent(() => import('./index.activity.vue')); | ||||||
|  | @ -156,29 +156,6 @@ const age = $computed(() => { | ||||||
| 	return calcAge(props.user.birthday); | 	return calcAge(props.user.birthday); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| function birthdayEffect() { |  | ||||||
| 	const duration = 1000 * 5; |  | ||||||
| 	const animationEnd = Date.now() + duration; |  | ||||||
| 	const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: os.claimZIndex('high') }; |  | ||||||
| 
 |  | ||||||
| 	function randomInRange(min, max) { |  | ||||||
| 		return Math.random() * (max - min) + min; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	const interval = setInterval(() => { |  | ||||||
| 		const timeLeft = animationEnd - Date.now(); |  | ||||||
| 
 |  | ||||||
| 		if (timeLeft <= 0) { |  | ||||||
| 			return clearInterval(interval); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		const particleCount = 50 * (timeLeft / duration); |  | ||||||
| 		// since particles fall down, start a bit higher than random |  | ||||||
| 		confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 } })); |  | ||||||
| 		confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 } })); |  | ||||||
| 	}, 250); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function menu(ev) { | function menu(ev) { | ||||||
| 	os.popupMenu(getUserMenu(props.user, router), ev.currentTarget ?? ev.target); | 	os.popupMenu(getUserMenu(props.user, router), ev.currentTarget ?? ev.target); | ||||||
| } | } | ||||||
|  | @ -211,7 +188,7 @@ onMounted(() => { | ||||||
| 		const bm = parseInt(props.user.birthday.split('-')[1]); | 		const bm = parseInt(props.user.birthday.split('-')[1]); | ||||||
| 		const bd = parseInt(props.user.birthday.split('-')[2]); | 		const bd = parseInt(props.user.birthday.split('-')[2]); | ||||||
| 		if (m === bm && d === bd) { | 		if (m === bm && d === bd) { | ||||||
| 			birthdayEffect(); | 			confetti(); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
|  |  | ||||||
							
								
								
									
										25
									
								
								packages/frontend/src/scripts/confetti.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								packages/frontend/src/scripts/confetti.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | ||||||
|  | import _confetti from 'canvas-confetti'; | ||||||
|  | import * as os from '@/os'; | ||||||
|  | 
 | ||||||
|  | export function confetti() { | ||||||
|  | 	const duration = 1000 * 5; | ||||||
|  | 	const animationEnd = Date.now() + duration; | ||||||
|  | 	const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: os.claimZIndex('high') }; | ||||||
|  | 
 | ||||||
|  | 	function randomInRange(min, max) { | ||||||
|  | 		return Math.random() * (max - min) + min; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	const interval = setInterval(() => { | ||||||
|  | 		const timeLeft = animationEnd - Date.now(); | ||||||
|  | 
 | ||||||
|  | 		if (timeLeft <= 0) { | ||||||
|  | 			return clearInterval(interval); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		const particleCount = 50 * (timeLeft / duration); | ||||||
|  | 		// since particles fall down, start a bit higher than random
 | ||||||
|  | 		_confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 } })); | ||||||
|  | 		_confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 } })); | ||||||
|  | 	}, 250); | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue