From ed0885ce5c592a2cb3755d7a43faa95845f06576 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 22 Apr 2018 17:32:56 +0900
Subject: [PATCH] #1533

---
 .../views/components/notifications.vue        | 344 +++++++++---------
 1 file changed, 178 insertions(+), 166 deletions(-)

diff --git a/src/client/app/desktop/views/components/notifications.vue b/src/client/app/desktop/views/components/notifications.vue
index f665f3d76c..47463b8b5b 100644
--- a/src/client/app/desktop/views/components/notifications.vue
+++ b/src/client/app/desktop/views/components/notifications.vue
@@ -1,96 +1,98 @@
 <template>
 <div class="mk-notifications">
 	<div class="notifications" v-if="notifications.length != 0">
-		<template v-for="(notification, i) in _notifications">
-			<div class="notification" :class="notification.type" :key="notification.id">
-				<mk-time :time="notification.createdAt"/>
-				<template v-if="notification.type == 'reaction'">
-					<router-link class="avatar-anchor" :to="notification.user | userPage" v-user-preview="notification.user.id">
-						<img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
-					</router-link>
-					<div class="text">
-						<p>
-							<mk-reaction-icon :reaction="notification.reaction"/>
-							<router-link :to="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</router-link>
-						</p>
-						<router-link class="note-ref" :to="notification.note | notePage">
-							%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%
+		<transition-group name="mk-notifications" class="transition">
+			<template v-for="(notification, i) in _notifications">
+				<div class="notification" :class="notification.type" :key="notification.id">
+					<mk-time :time="notification.createdAt"/>
+					<template v-if="notification.type == 'reaction'">
+						<router-link class="avatar-anchor" :to="notification.user | userPage" v-user-preview="notification.user.id">
+							<img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
 						</router-link>
-					</div>
-				</template>
-				<template v-if="notification.type == 'renote'">
-					<router-link class="avatar-anchor" :to="notification.note.user | userPage" v-user-preview="notification.note.userId">
-						<img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
-					</router-link>
-					<div class="text">
-						<p>%fa:retweet%
-							<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
-						</p>
-						<router-link class="note-ref" :to="notification.note | notePage">
-							%fa:quote-left%{{ getNoteSummary(notification.note.renote) }}%fa:quote-right%
+						<div class="text">
+							<p>
+								<mk-reaction-icon :reaction="notification.reaction"/>
+								<router-link :to="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</router-link>
+							</p>
+							<router-link class="note-ref" :to="notification.note | notePage">
+								%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%
+							</router-link>
+						</div>
+					</template>
+					<template v-if="notification.type == 'renote'">
+						<router-link class="avatar-anchor" :to="notification.note.user | userPage" v-user-preview="notification.note.userId">
+							<img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
 						</router-link>
-					</div>
-				</template>
-				<template v-if="notification.type == 'quote'">
-					<router-link class="avatar-anchor" :to="notification.note.user | userPage" v-user-preview="notification.note.userId">
-						<img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
-					</router-link>
-					<div class="text">
-						<p>%fa:quote-left%
-							<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
-						</p>
-						<router-link class="note-preview" :to="notification.note | notePage">{{ getNoteSummary(notification.note) }}</router-link>
-					</div>
-				</template>
-				<template v-if="notification.type == 'follow'">
-					<router-link class="avatar-anchor" :to="notification.user | userPage" v-user-preview="notification.user.id">
-						<img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
-					</router-link>
-					<div class="text">
-						<p>%fa:user-plus%
-							<router-link :to="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</router-link>
-						</p>
-					</div>
-				</template>
-				<template v-if="notification.type == 'reply'">
-					<router-link class="avatar-anchor" :to="notification.note.user | userPage" v-user-preview="notification.note.userId">
-						<img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
-					</router-link>
-					<div class="text">
-						<p>%fa:reply%
-							<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
-						</p>
-						<router-link class="note-preview" :to="notification.note | notePage">{{ getNoteSummary(notification.note) }}</router-link>
-					</div>
-				</template>
-				<template v-if="notification.type == 'mention'">
-					<router-link class="avatar-anchor" :to="notification.note.user | userPage" v-user-preview="notification.note.userId">
-						<img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
-					</router-link>
-					<div class="text">
-						<p>%fa:at%
-							<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
-						</p>
-						<a class="note-preview" :href="notification.note | notePage">{{ getNoteSummary(notification.note) }}</a>
-					</div>
-				</template>
-				<template v-if="notification.type == 'poll_vote'">
-					<router-link class="avatar-anchor" :to="notification.user | userPage" v-user-preview="notification.user.id">
-						<img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
-					</router-link>
-					<div class="text">
-						<p>%fa:chart-pie%<a :href="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</a></p>
-						<router-link class="note-ref" :to="notification.note | notePage">
-							%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%
+						<div class="text">
+							<p>%fa:retweet%
+								<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
+							</p>
+							<router-link class="note-ref" :to="notification.note | notePage">
+								%fa:quote-left%{{ getNoteSummary(notification.note.renote) }}%fa:quote-right%
+							</router-link>
+						</div>
+					</template>
+					<template v-if="notification.type == 'quote'">
+						<router-link class="avatar-anchor" :to="notification.note.user | userPage" v-user-preview="notification.note.userId">
+							<img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
 						</router-link>
-					</div>
-				</template>
-			</div>
-			<p class="date" v-if="i != notifications.length - 1 && notification._date != _notifications[i + 1]._date" :key="notification.id + '-time'">
-				<span>%fa:angle-up%{{ notification._datetext }}</span>
-				<span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span>
-			</p>
-		</template>
+						<div class="text">
+							<p>%fa:quote-left%
+								<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
+							</p>
+							<router-link class="note-preview" :to="notification.note | notePage">{{ getNoteSummary(notification.note) }}</router-link>
+						</div>
+					</template>
+					<template v-if="notification.type == 'follow'">
+						<router-link class="avatar-anchor" :to="notification.user | userPage" v-user-preview="notification.user.id">
+							<img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
+						</router-link>
+						<div class="text">
+							<p>%fa:user-plus%
+								<router-link :to="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</router-link>
+							</p>
+						</div>
+					</template>
+					<template v-if="notification.type == 'reply'">
+						<router-link class="avatar-anchor" :to="notification.note.user | userPage" v-user-preview="notification.note.userId">
+							<img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
+						</router-link>
+						<div class="text">
+							<p>%fa:reply%
+								<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
+							</p>
+							<router-link class="note-preview" :to="notification.note | notePage">{{ getNoteSummary(notification.note) }}</router-link>
+						</div>
+					</template>
+					<template v-if="notification.type == 'mention'">
+						<router-link class="avatar-anchor" :to="notification.note.user | userPage" v-user-preview="notification.note.userId">
+							<img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
+						</router-link>
+						<div class="text">
+							<p>%fa:at%
+								<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
+							</p>
+							<a class="note-preview" :href="notification.note | notePage">{{ getNoteSummary(notification.note) }}</a>
+						</div>
+					</template>
+					<template v-if="notification.type == 'poll_vote'">
+						<router-link class="avatar-anchor" :to="notification.user | userPage" v-user-preview="notification.user.id">
+							<img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
+						</router-link>
+						<div class="text">
+							<p>%fa:chart-pie%<a :href="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</a></p>
+							<router-link class="note-ref" :to="notification.note | notePage">
+								%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%
+							</router-link>
+						</div>
+					</template>
+				</div>
+				<p class="date" v-if="i != notifications.length - 1 && notification._date != _notifications[i + 1]._date" :key="notification.id + '-time'">
+					<span>%fa:angle-up%{{ notification._datetext }}</span>
+					<span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span>
+				</p>
+			</template>
+		</transition-group>
 	</div>
 	<button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
 		<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:!common.loading%' : '%i18n:!@more%' }}
@@ -186,97 +188,107 @@ export default Vue.extend({
 
 <style lang="stylus" scoped>
 root(isDark)
+	.transition
+		.mk-notifications-enter
+		.mk-notifications-leave-to
+			opacity 0
+			transform translateY(-30px)
+
+		> *
+			transition transform .3s ease, opacity .3s ease
+
 	> .notifications
-		> .notification
-			margin 0
-			padding 16px
-			overflow-wrap break-word
-			font-size 0.9em
-			border-bottom solid 1px isDark ? #1c2023 : rgba(0, 0, 0, 0.05)
+		> *
+			> .notification
+				margin 0
+				padding 16px
+				overflow-wrap break-word
+				font-size 0.9em
+				border-bottom solid 1px isDark ? #1c2023 : rgba(0, 0, 0, 0.05)
 
-			&:last-child
-				border-bottom none
+				&:last-child
+					border-bottom none
 
-			> .mk-time
-				display inline
-				position absolute
-				top 16px
-				right 12px
-				vertical-align top
-				color isDark ? #606984 : rgba(0, 0, 0, 0.6)
-				font-size small
+				> .mk-time
+					display inline
+					position absolute
+					top 16px
+					right 12px
+					vertical-align top
+					color isDark ? #606984 : rgba(0, 0, 0, 0.6)
+					font-size small
 
-			&:after
-				content ""
-				display block
-				clear both
-
-			> .avatar-anchor
-				display block
-				float left
-				position -webkit-sticky
-				position sticky
-				top 16px
-
-				> img
+				&:after
+					content ""
 					display block
-					min-width 36px
-					min-height 36px
-					max-width 36px
-					max-height 36px
-					border-radius 6px
+					clear both
 
-			> .text
-				float right
-				width calc(100% - 36px)
-				padding-left 8px
+				> .avatar-anchor
+					display block
+					float left
+					position -webkit-sticky
+					position sticky
+					top 16px
 
-				p
-					margin 0
+					> img
+						display block
+						min-width 36px
+						min-height 36px
+						max-width 36px
+						max-height 36px
+						border-radius 6px
 
-					i, .mk-reaction-icon
-						margin-right 4px
+				> .text
+					float right
+					width calc(100% - 36px)
+					padding-left 8px
 
-			.note-preview
-				color isDark ? #c2cad4 : rgba(0, 0, 0, 0.7)
+					p
+						margin 0
 
-			.note-ref
-				color isDark ? #c2cad4 : rgba(0, 0, 0, 0.7)
+						i, .mk-reaction-icon
+							margin-right 4px
+
+				.note-preview
+					color isDark ? #c2cad4 : rgba(0, 0, 0, 0.7)
+
+				.note-ref
+					color isDark ? #c2cad4 : rgba(0, 0, 0, 0.7)
+
+					[data-fa]
+						font-size 1em
+						font-weight normal
+						font-style normal
+						display inline-block
+						margin-right 3px
+
+				&.renote, &.quote
+					.text p i
+						color #77B255
+
+				&.follow
+					.text p i
+						color #53c7ce
+
+				&.reply, &.mention
+					.text p i
+						color #555
+
+			> .date
+				display block
+				margin 0
+				line-height 32px
+				text-align center
+				font-size 0.8em
+				color isDark ? #666b79 : #aaa
+				background isDark ? #242731 : #fdfdfd
+				border-bottom solid 1px isDark ? #1c2023 : rgba(0, 0, 0, 0.05)
+
+				span
+					margin 0 16px
 
 				[data-fa]
-					font-size 1em
-					font-weight normal
-					font-style normal
-					display inline-block
-					margin-right 3px
-
-			&.renote, &.quote
-				.text p i
-					color #77B255
-
-			&.follow
-				.text p i
-					color #53c7ce
-
-			&.reply, &.mention
-				.text p i
-					color #555
-
-		> .date
-			display block
-			margin 0
-			line-height 32px
-			text-align center
-			font-size 0.8em
-			color isDark ? #666b79 : #aaa
-			background isDark ? #242731 : #fdfdfd
-			border-bottom solid 1px isDark ? #1c2023 : rgba(0, 0, 0, 0.05)
-
-			span
-				margin 0 16px
-
-			[data-fa]
-				margin-right 8px
+					margin-right 8px
 
 	> .more
 		display block