🎨
This commit is contained in:
		
							parent
							
								
									50043047aa
								
							
						
					
					
						commit
						86e88647fd
					
				
					 3 changed files with 90 additions and 74 deletions
				
			
		|  | @ -1,68 +0,0 @@ | ||||||
| <template> |  | ||||||
| <div class="mk-notification-toast" :style="{ zIndex }"> |  | ||||||
| 	<Transition :name="$store.state.animation ? 'notification-toast' : ''" appear @after-leave="$emit('closed')"> |  | ||||||
| 		<XNotification v-if="showing" :notification="notification" class="notification _acrylic"/> |  | ||||||
| 	</Transition> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
| 
 |  | ||||||
| <script lang="ts" setup> |  | ||||||
| import { onMounted } from 'vue'; |  | ||||||
| import XNotification from '@/components/MkNotification.vue'; |  | ||||||
| import * as os from '@/os'; |  | ||||||
| 
 |  | ||||||
| defineProps<{ |  | ||||||
| 	notification: any; // TODO |  | ||||||
| }>(); |  | ||||||
| 
 |  | ||||||
| const emit = defineEmits<{ |  | ||||||
| 	(ev: 'closed'): void; |  | ||||||
| }>(); |  | ||||||
| 
 |  | ||||||
| const zIndex = os.claimZIndex('high'); |  | ||||||
| let showing = $ref(true); |  | ||||||
| 
 |  | ||||||
| onMounted(() => { |  | ||||||
| 	window.setTimeout(() => { |  | ||||||
| 		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; |  | ||||||
| 	container-type: inline-size; |  | ||||||
| 
 |  | ||||||
| 	@media (max-width: 700px) { |  | ||||||
| 		top: initial; |  | ||||||
| 		bottom: 112px; |  | ||||||
| 		padding: 0 16px; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@media (max-width: 500px) { |  | ||||||
| 		bottom: calc(env(safe-area-inset-bottom, 0px) + 92px); |  | ||||||
| 		padding: 0 8px; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	> .notification { |  | ||||||
| 		height: 100%; |  | ||||||
| 		box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); |  | ||||||
| 		border-radius: 8px; |  | ||||||
| 		overflow: hidden; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
|  | @ -9,6 +9,10 @@ | ||||||
| 
 | 
 | ||||||
| <XUpload v-if="uploads.length > 0"/> | <XUpload v-if="uploads.length > 0"/> | ||||||
| 
 | 
 | ||||||
|  | <TransitionGroup :name="$store.state.animation ? 'notification' : ''" tag="div" class="notifications"> | ||||||
|  | 	<XNotification v-for="notification in notifications" :key="notification.id" :notification="notification" class="notification"/> | ||||||
|  | </TransitionGroup> | ||||||
|  | 
 | ||||||
| <XStreamIndicator/> | <XStreamIndicator/> | ||||||
| 
 | 
 | ||||||
| <div v-if="pendingApiRequestsCount > 0" id="wait"></div> | <div v-if="pendingApiRequestsCount > 0" id="wait"></div> | ||||||
|  | @ -19,8 +23,10 @@ | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
| import { defineAsyncComponent } from 'vue'; | import { defineAsyncComponent, nextTick } from 'vue'; | ||||||
|  | import * as misskey from 'misskey-js'; | ||||||
| import { swInject } from './sw-inject'; | import { swInject } from './sw-inject'; | ||||||
|  | import XNotification from './notification.vue'; | ||||||
| import { popup, popups, pendingApiRequestsCount } from '@/os'; | import { popup, popups, pendingApiRequestsCount } from '@/os'; | ||||||
| import { uploads } from '@/scripts/upload'; | import { uploads } from '@/scripts/upload'; | ||||||
| import * as sound from '@/scripts/sound'; | import * as sound from '@/scripts/sound'; | ||||||
|  | @ -33,7 +39,9 @@ const XUpload = defineAsyncComponent(() => import('./upload.vue')); | ||||||
| 
 | 
 | ||||||
| const dev = _DEV_; | const dev = _DEV_; | ||||||
| 
 | 
 | ||||||
| const onNotification = notification => { | let notifications = $ref<misskey.entities.Notification[]>([]); | ||||||
|  | 
 | ||||||
|  | function onNotification(notification) { | ||||||
| 	if ($i.mutingNotificationTypes.includes(notification.type)) return; | 	if ($i.mutingNotificationTypes.includes(notification.type)) return; | ||||||
| 
 | 
 | ||||||
| 	if (document.visibilityState === 'visible') { | 	if (document.visibilityState === 'visible') { | ||||||
|  | @ -41,13 +49,18 @@ const onNotification = notification => { | ||||||
| 			id: notification.id, | 			id: notification.id, | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| 		popup(defineAsyncComponent(() => import('@/components/MkNotificationToast.vue')), { | 		notifications.unshift(notification); | ||||||
| 			notification, | 		window.setTimeout(() => { | ||||||
| 		}, {}, 'closed'); | 			if (notifications.length > 3) notifications.pop(); | ||||||
|  | 		}, 500); | ||||||
|  | 
 | ||||||
|  | 		window.setTimeout(() => { | ||||||
|  | 			notifications = notifications.filter(x => x.id !== notification.id); | ||||||
|  | 		}, 6000); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	sound.play('notification'); | 	sound.play('notification'); | ||||||
| }; | } | ||||||
| 
 | 
 | ||||||
| if ($i) { | if ($i) { | ||||||
| 	const connection = stream.useChannel('main', null, 'UI'); | 	const connection = stream.useChannel('main', null, 'UI'); | ||||||
|  | @ -60,6 +73,53 @@ if ($i) { | ||||||
| } | } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .notification-move, .notification-enter-active, .notification-leave-active { | ||||||
|  | 	transition: opacity 0.3s, transform 0.3s !important; | ||||||
|  | } | ||||||
|  | .notification-enter-from, .notification-leave-to { | ||||||
|  | 	opacity: 0; | ||||||
|  | 	transform: translateX(-250px); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .notifications { | ||||||
|  | 	position: fixed; | ||||||
|  | 	z-index: 3900000; | ||||||
|  | 	left: 0; | ||||||
|  | 	width: 250px; | ||||||
|  | 	top: 32px; | ||||||
|  | 	padding: 0 32px; | ||||||
|  | 	pointer-events: none; | ||||||
|  | 	container-type: inline-size; | ||||||
|  | 
 | ||||||
|  | 	> .notification { | ||||||
|  | 		& + .notification { | ||||||
|  | 			margin-top: 8px; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@media (max-width: 700px) { | ||||||
|  | 		top: initial; | ||||||
|  | 		bottom: 112px; | ||||||
|  | 		padding: 0 16px; | ||||||
|  | 		display: flex; | ||||||
|  | 		flex-direction: column-reverse; | ||||||
|  | 
 | ||||||
|  | 		> .notification { | ||||||
|  | 			& + .notification { | ||||||
|  | 				margin-top: 0; | ||||||
|  | 				margin-bottom: 8px; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@media (max-width: 500px) { | ||||||
|  | 		bottom: calc(env(safe-area-inset-bottom, 0px) + 92px); | ||||||
|  | 		padding: 0 8px; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | </style> | ||||||
|  | 
 | ||||||
| <style lang="scss"> | <style lang="scss"> | ||||||
| @keyframes dev-ticker-blink { | @keyframes dev-ticker-blink { | ||||||
| 	0% { opacity: 1; } | 	0% { opacity: 1; } | ||||||
|  |  | ||||||
							
								
								
									
										24
									
								
								packages/frontend/src/ui/_common_/notification.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								packages/frontend/src/ui/_common_/notification.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | ||||||
|  | <template> | ||||||
|  | <div :class="$style.root"> | ||||||
|  | 	<XNotification :notification="notification" class="notification _acrylic"/> | ||||||
|  | </div> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import { } from 'vue'; | ||||||
|  | import * as misskey from 'misskey-js'; | ||||||
|  | import XNotification from '@/components/MkNotification.vue'; | ||||||
|  | 
 | ||||||
|  | defineProps<{ | ||||||
|  | 	notification: misskey.entities.Notification; | ||||||
|  | }>(); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style lang="scss" module> | ||||||
|  | .root { | ||||||
|  | 	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); | ||||||
|  | 	border-radius: 8px; | ||||||
|  | 	overflow: clip; | ||||||
|  | 	contain: content; | ||||||
|  | } | ||||||
|  | </style> | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue