feat(client): improve toast component and show welcome message
This commit is contained in:
		
							parent
							
								
									f9e3fd7001
								
							
						
					
					
						commit
						d6e85ffb59
					
				|  | @ -816,6 +816,7 @@ hide: "隠す" | |||
| leaveGroup: "グループから抜ける" | ||||
| leaveGroupConfirm: "「{name}」から抜けますか?" | ||||
| useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示" | ||||
| welcomeBackWithName: "おかえりなさい、{name}さん" | ||||
| 
 | ||||
| _emailUnavailable: | ||||
|   used: "既に使用されています" | ||||
|  |  | |||
|  | @ -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> | ||||
| <div class="mk-toast" :style="{ zIndex }"> | ||||
| 	<transition name="notification-slide" appear @after-leave="$emit('closed')"> | ||||
| 		<XNotification v-if="showing" :notification="notification" class="notification _acrylic"/> | ||||
| <div class="mk-toast"> | ||||
| 	<transition name="toast" appear @after-leave="$emit('closed')"> | ||||
| 		<div v-if="showing" class="body _acrylic" :style="{ zIndex }"> | ||||
| 			<div class="message"> | ||||
| 				{{ message }} | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</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 | ||||
| 		} | ||||
| 		message: { | ||||
| 			type: String, | ||||
| 			required: true, | ||||
| 		}, | ||||
| 	}, | ||||
| 	emits: ['closed'], | ||||
| 	data() { | ||||
|  | @ -31,44 +31,41 @@ export default defineComponent({ | |||
| 	mounted() { | ||||
| 		setTimeout(() => { | ||||
| 			this.showing = false; | ||||
| 		}, 6000); | ||||
| 		}, 4000); | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <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; | ||||
| } | ||||
| .notification-slide-enter-from, .notification-slide-leave-to { | ||||
| .toast-enter-from, .toast-leave-to { | ||||
| 	opacity: 0; | ||||
| 	transform: translateX(-250px); | ||||
| 	transform: translateY(calc(0px - (100% - 32px))); | ||||
| } | ||||
| 
 | ||||
| .mk-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%; | ||||
| 	> .body { | ||||
| 		position: fixed; | ||||
| 		left: 0; | ||||
| 		right: 0; | ||||
| 		top: 0; | ||||
| 		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: 8px; | ||||
| 		overflow: hidden; | ||||
| 		border-radius: 0 0 8px 8px; | ||||
| 		overflow: clip; | ||||
| 		text-align: center; | ||||
| 		pointer-events: none; | ||||
| 
 | ||||
| 		> .message { | ||||
| 			padding: 16px 24px; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ import { router } from '@/router'; | |||
| import { applyTheme } from '@/scripts/theme'; | ||||
| import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; | ||||
| 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 { $i, refreshAccount, login, updateAccount, signout } from '@/account'; | ||||
| 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.permission === 'default') { | ||||
|  |  | |||
|  | @ -221,7 +221,9 @@ export function modalPageWindow(path: string) { | |||
| } | ||||
| 
 | ||||
| export function toast(message: string) { | ||||
| 	// TODO
 | ||||
| 	popup(import('@/components/toast.vue'), { | ||||
| 		message | ||||
| 	}, {}, 'closed'); | ||||
| } | ||||
| 
 | ||||
| export function alert(props: { | ||||
|  |  | |||
|  | @ -34,7 +34,7 @@ export default defineComponent({ | |||
| 					id: notification.id | ||||
| 				}); | ||||
| 
 | ||||
| 				popup(import('@/components/toast.vue'), { | ||||
| 				popup(import('@/components/notification-toast.vue'), { | ||||
| 					notification | ||||
| 				}, {}, 'closed'); | ||||
| 			} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue