feat(client): improve toast component and show welcome message
This commit is contained in:
		
							parent
							
								
									f9e3fd7001
								
							
						
					
					
						commit
						d6e85ffb59
					
				
					 6 changed files with 126 additions and 40 deletions
				
			
		|  | @ -816,6 +816,7 @@ hide: "隠す" | ||||||
| leaveGroup: "グループから抜ける" | leaveGroup: "グループから抜ける" | ||||||
| leaveGroupConfirm: "「{name}」から抜けますか?" | leaveGroupConfirm: "「{name}」から抜けますか?" | ||||||
| useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示" | useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示" | ||||||
|  | welcomeBackWithName: "おかえりなさい、{name}さん" | ||||||
| 
 | 
 | ||||||
| _emailUnavailable: | _emailUnavailable: | ||||||
|   used: "既に使用されています" |   used: "既に使用されています" | ||||||
|  |  | ||||||
							
								
								
									
										74
									
								
								packages/client/src/components/notification-toast.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								packages/client/src/components/notification-toast.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,74 @@ | ||||||
|  | <template> | ||||||
|  | <div class="mk-notification-toast" :style="{ zIndex }"> | ||||||
|  | 	<transition name="notification-toast" appear @after-leave="$emit('closed')"> | ||||||
|  | 		<XNotification v-if="showing" :notification="notification" class="notification _acrylic"/> | ||||||
|  | 	</transition> | ||||||
|  | </div> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script lang="ts"> | ||||||
|  | import { defineComponent } from 'vue'; | ||||||
|  | import XNotification from './notification.vue'; | ||||||
|  | import * as os from '@/os'; | ||||||
|  | 
 | ||||||
|  | export default defineComponent({ | ||||||
|  | 	components: { | ||||||
|  | 		XNotification | ||||||
|  | 	}, | ||||||
|  | 	props: { | ||||||
|  | 		notification: { | ||||||
|  | 			type: Object, | ||||||
|  | 			required: true | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	emits: ['closed'], | ||||||
|  | 	data() { | ||||||
|  | 		return { | ||||||
|  | 			showing: true, | ||||||
|  | 			zIndex: os.claimZIndex('high'), | ||||||
|  | 		}; | ||||||
|  | 	}, | ||||||
|  | 	mounted() { | ||||||
|  | 		setTimeout(() => { | ||||||
|  | 			this.showing = false; | ||||||
|  | 		}, 6000); | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .notification-toast-enter-active, .notification-toast-leave-active { | ||||||
|  | 	transition: opacity 0.3s, transform 0.3s !important; | ||||||
|  | } | ||||||
|  | .notification-toast-enter-from, .notification-toast-leave-to { | ||||||
|  | 	opacity: 0; | ||||||
|  | 	transform: translateX(-250px); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .mk-notification-toast { | ||||||
|  | 	position: fixed; | ||||||
|  | 	left: 0; | ||||||
|  | 	width: 250px; | ||||||
|  | 	top: 32px; | ||||||
|  | 	padding: 0 32px; | ||||||
|  | 	pointer-events: none; | ||||||
|  | 
 | ||||||
|  | 	@media (max-width: 700px) { | ||||||
|  | 		top: initial; | ||||||
|  | 		bottom: 112px; | ||||||
|  | 		padding: 0 16px; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@media (max-width: 500px) { | ||||||
|  | 		bottom: 92px; | ||||||
|  | 		padding: 0 8px; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	> .notification { | ||||||
|  | 		height: 100%; | ||||||
|  | 		box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); | ||||||
|  | 		border-radius: 8px; | ||||||
|  | 		overflow: hidden; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | </style> | ||||||
|  | @ -1,25 +1,25 @@ | ||||||
| <template> | <template> | ||||||
| <div class="mk-toast" :style="{ zIndex }"> | <div class="mk-toast"> | ||||||
| 	<transition name="notification-slide" appear @after-leave="$emit('closed')"> | 	<transition name="toast" appear @after-leave="$emit('closed')"> | ||||||
| 		<XNotification v-if="showing" :notification="notification" class="notification _acrylic"/> | 		<div v-if="showing" class="body _acrylic" :style="{ zIndex }"> | ||||||
|  | 			<div class="message"> | ||||||
|  | 				{{ message }} | ||||||
|  | 			</div> | ||||||
|  | 		</div> | ||||||
| 	</transition> | 	</transition> | ||||||
| </div> | </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import { defineComponent } from 'vue'; | import { defineComponent } from 'vue'; | ||||||
| import XNotification from './notification.vue'; |  | ||||||
| import * as os from '@/os'; | import * as os from '@/os'; | ||||||
| 
 | 
 | ||||||
| export default defineComponent({ | export default defineComponent({ | ||||||
| 	components: { |  | ||||||
| 		XNotification |  | ||||||
| 	}, |  | ||||||
| 	props: { | 	props: { | ||||||
| 		notification: { | 		message: { | ||||||
| 			type: Object, | 			type: String, | ||||||
| 			required: true | 			required: true, | ||||||
| 		} | 		}, | ||||||
| 	}, | 	}, | ||||||
| 	emits: ['closed'], | 	emits: ['closed'], | ||||||
| 	data() { | 	data() { | ||||||
|  | @ -31,44 +31,41 @@ export default defineComponent({ | ||||||
| 	mounted() { | 	mounted() { | ||||||
| 		setTimeout(() => { | 		setTimeout(() => { | ||||||
| 			this.showing = false; | 			this.showing = false; | ||||||
| 		}, 6000); | 		}, 4000); | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
| .notification-slide-enter-active, .notification-slide-leave-active { | .toast-enter-active, .toast-leave-active { | ||||||
| 	transition: opacity 0.3s, transform 0.3s !important; | 	transition: opacity 0.3s, transform 0.3s !important; | ||||||
| } | } | ||||||
| .notification-slide-enter-from, .notification-slide-leave-to { | .toast-enter-from, .toast-leave-to { | ||||||
| 	opacity: 0; | 	opacity: 0; | ||||||
| 	transform: translateX(-250px); | 	transform: translateY(calc(0px - (100% - 32px))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .mk-toast { | .mk-toast { | ||||||
|  | 	> .body { | ||||||
| 		position: fixed; | 		position: fixed; | ||||||
| 		left: 0; | 		left: 0; | ||||||
| 	width: 250px; | 		right: 0; | ||||||
| 	top: 32px; | 		top: 0; | ||||||
| 	padding: 0 32px; | 		margin: 0 auto; | ||||||
|  | 		padding-top: 32px; | ||||||
|  | 		margin-top: -32px; | ||||||
|  | 		min-width: 300px; | ||||||
|  | 		max-width: calc(100% - 32px); | ||||||
|  | 		width: min-content; | ||||||
|  | 		box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); | ||||||
|  | 		border-radius: 0 0 8px 8px; | ||||||
|  | 		overflow: clip; | ||||||
|  | 		text-align: center; | ||||||
| 		pointer-events: none; | 		pointer-events: none; | ||||||
| 
 | 
 | ||||||
| 	@media (max-width: 700px) { | 		> .message { | ||||||
| 		top: initial; | 			padding: 16px 24px; | ||||||
| 		bottom: 112px; |  | ||||||
| 		padding: 0 16px; |  | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 	@media (max-width: 500px) { |  | ||||||
| 		bottom: 92px; |  | ||||||
| 		padding: 0 8px; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	> .notification { |  | ||||||
| 		height: 100%; |  | ||||||
| 		box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); |  | ||||||
| 		border-radius: 8px; |  | ||||||
| 		overflow: hidden; |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| </style> | </style> | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ import { router } from '@/router'; | ||||||
| import { applyTheme } from '@/scripts/theme'; | import { applyTheme } from '@/scripts/theme'; | ||||||
| import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; | import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| import { stream, confirm, alert, post, popup } from '@/os'; | import { stream, confirm, alert, post, popup, toast } from '@/os'; | ||||||
| import * as sound from '@/scripts/sound'; | import * as sound from '@/scripts/sound'; | ||||||
| import { $i, refreshAccount, login, updateAccount, signout } from '@/account'; | import { $i, refreshAccount, login, updateAccount, signout } from '@/account'; | ||||||
| import { defaultStore, ColdDeviceStorage } from '@/store'; | import { defaultStore, ColdDeviceStorage } from '@/store'; | ||||||
|  | @ -342,6 +342,18 @@ if ($i) { | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	const lastUsed = localStorage.getItem('lastUsed'); | ||||||
|  | 	if (lastUsed) { | ||||||
|  | 		const lastUsedDate = parseInt(lastUsed, 10); | ||||||
|  | 		// 二時間以上前なら
 | ||||||
|  | 		if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) { | ||||||
|  | 			toast(i18n.t('welcomeBackWithName', { | ||||||
|  | 				name: $i.name || $i.username, | ||||||
|  | 			})); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	localStorage.setItem('lastUsed', Date.now().toString()); | ||||||
|  | 
 | ||||||
| 	if ('Notification' in window) { | 	if ('Notification' in window) { | ||||||
| 		// 許可を得ていなかったらリクエスト
 | 		// 許可を得ていなかったらリクエスト
 | ||||||
| 		if (Notification.permission === 'default') { | 		if (Notification.permission === 'default') { | ||||||
|  |  | ||||||
|  | @ -221,7 +221,9 @@ export function modalPageWindow(path: string) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function toast(message: string) { | export function toast(message: string) { | ||||||
| 	// TODO
 | 	popup(import('@/components/toast.vue'), { | ||||||
|  | 		message | ||||||
|  | 	}, {}, 'closed'); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function alert(props: { | export function alert(props: { | ||||||
|  |  | ||||||
|  | @ -34,7 +34,7 @@ export default defineComponent({ | ||||||
| 					id: notification.id | 					id: notification.id | ||||||
| 				}); | 				}); | ||||||
| 
 | 
 | ||||||
| 				popup(import('@/components/toast.vue'), { | 				popup(import('@/components/notification-toast.vue'), { | ||||||
| 					notification | 					notification | ||||||
| 				}, {}, 'closed'); | 				}, {}, 'closed'); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue