forked from Mirrors/elk
feat: grouped follow notification
This commit is contained in:
parent
07209a7d29
commit
a6406abc52
6 changed files with 118 additions and 25 deletions
|
@ -29,24 +29,26 @@ const { items, prevItems, update, state, endAnchor, error } = usePaginator(pagin
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<slot v-if="prevItems.length" name="updater" v-bind="{ number: prevItems.length, update }" />
|
<slot v-if="prevItems.length" name="updater" v-bind="{ number: prevItems.length, update }" />
|
||||||
<template v-if="virtualScroller">
|
<slot name="items" :items="items">
|
||||||
<DynamicScroller
|
<template v-if="virtualScroller">
|
||||||
v-slot="{ item, active }"
|
<DynamicScroller
|
||||||
:items="items"
|
v-slot="{ item, active }"
|
||||||
:min-item-size="200"
|
:items="items"
|
||||||
:key-field="keyProp"
|
:min-item-size="200"
|
||||||
page-mode
|
:key-field="keyProp"
|
||||||
>
|
page-mode
|
||||||
<slot :item="item" :active="active" />
|
>
|
||||||
</DynamicScroller>
|
<slot :item="item" :active="active" />
|
||||||
</template>
|
</DynamicScroller>
|
||||||
<template v-else>
|
</template>
|
||||||
<slot
|
<template v-else>
|
||||||
v-for="item of items"
|
<slot
|
||||||
:key="item[keyProp]"
|
v-for="item of items"
|
||||||
:item="item"
|
:key="item[keyProp]"
|
||||||
/>
|
:item="item"
|
||||||
</template>
|
/>
|
||||||
|
</template>
|
||||||
|
</slot>
|
||||||
<div ref="endAnchor" />
|
<div ref="endAnchor" />
|
||||||
<slot v-if="state === 'loading'" name="loading">
|
<slot v-if="state === 'loading'" name="loading">
|
||||||
<div p5 text-center flex="~ col" items-center animate-pulse>
|
<div p5 text-center flex="~ col" items-center animate-pulse>
|
||||||
|
|
38
components/notification/NotificationGroupedFollow.vue
Normal file
38
components/notification/NotificationGroupedFollow.vue
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { GroupedNotifications } from '~/types'
|
||||||
|
|
||||||
|
const { items } = defineProps<{
|
||||||
|
items: GroupedNotifications
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const count = computed(() => items.items.length)
|
||||||
|
const isExpanded = ref(false)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<article flex flex-col>
|
||||||
|
<div flex ml-4 items-center>
|
||||||
|
<div i-ri:user-follow-fill mr-3 color-primary />
|
||||||
|
{{ $t('notification.followed_you_count', [`${count}`]) }}
|
||||||
|
</div>
|
||||||
|
<div v-if="isExpanded">
|
||||||
|
<AccountCard
|
||||||
|
v-for="item in items.items"
|
||||||
|
:key="item.id"
|
||||||
|
:account="item.account"
|
||||||
|
p3
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else flex="~ wrap gap-1" p4>
|
||||||
|
<AccountHoverWrapper
|
||||||
|
v-for="item in items.items"
|
||||||
|
:key="item.id"
|
||||||
|
:account="item.account"
|
||||||
|
>
|
||||||
|
<NuxtLink :to="getAccountPath(item.account)">
|
||||||
|
<AccountAvatar :account="item.account" w-8 h-8 />
|
||||||
|
</NuxtLink>
|
||||||
|
</AccountHoverWrapper>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</template>
|
|
@ -1,19 +1,64 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Notification, Paginator } from 'masto'
|
import type { Notification, Paginator } from 'masto'
|
||||||
|
import type { GroupedNotifications } from '~/types'
|
||||||
|
|
||||||
const { paginator } = defineProps<{
|
const { paginator } = defineProps<{
|
||||||
paginator: Paginator<any, Notification[]>
|
paginator: Paginator<any, Notification[]>
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
function groupItems(items: Notification[]): (Notification | GroupedNotifications)[] {
|
||||||
|
const results: (Notification | GroupedNotifications)[] = []
|
||||||
|
|
||||||
|
let id = 0
|
||||||
|
let followGroup: Notification[] = []
|
||||||
|
|
||||||
|
const bump = () => {
|
||||||
|
if (followGroup.length === 1) {
|
||||||
|
results.push(followGroup[0])
|
||||||
|
followGroup = []
|
||||||
|
}
|
||||||
|
else if (followGroup.length > 0) {
|
||||||
|
results.push({
|
||||||
|
id: `grouped-${id++}`,
|
||||||
|
type: 'grouped-follow',
|
||||||
|
items: followGroup,
|
||||||
|
})
|
||||||
|
followGroup = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.type === 'follow') {
|
||||||
|
followGroup.push(item)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bump()
|
||||||
|
results.push(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bump()
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CommonPaginator :paginator="paginator">
|
<CommonPaginator :paginator="paginator">
|
||||||
<template #default="{ item }">
|
<template #items="{ items }">
|
||||||
<NotificationCard
|
<template v-for="item of groupItems(items)" :key="item.id">
|
||||||
:notification="item"
|
<NotificationGroupedFollow
|
||||||
hover:bg-active
|
v-if="item.type === 'grouped-follow'"
|
||||||
border="b base" pt-4
|
:items="item"
|
||||||
/>
|
border="b base" pt-4
|
||||||
|
/>
|
||||||
|
<NotificationCard
|
||||||
|
v-else
|
||||||
|
:notification="item"
|
||||||
|
hover:bg-active
|
||||||
|
border="b base" pt-4
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</CommonPaginator>
|
</CommonPaginator>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -84,6 +84,7 @@
|
||||||
"notification": {
|
"notification": {
|
||||||
"favourited_post": "favourited your post",
|
"favourited_post": "favourited your post",
|
||||||
"followed_you": "followed you",
|
"followed_you": "followed you",
|
||||||
|
"followed_you_count": "{0} persons followed you",
|
||||||
"missing_type": "MISSING notification.type:",
|
"missing_type": "MISSING notification.type:",
|
||||||
"reblogged_post": "reblogged your post",
|
"reblogged_post": "reblogged your post",
|
||||||
"request_to_follow": "requested to follow you",
|
"request_to_follow": "requested to follow you",
|
||||||
|
|
|
@ -84,6 +84,7 @@
|
||||||
"notification": {
|
"notification": {
|
||||||
"favourited_post": "点赞了你的帖文",
|
"favourited_post": "点赞了你的帖文",
|
||||||
"followed_you": "关注了你",
|
"followed_you": "关注了你",
|
||||||
|
"followed_you_count": "{0} 人关注了你",
|
||||||
"missing_type": "未知的通知类型:",
|
"missing_type": "未知的通知类型:",
|
||||||
"reblogged_post": "转发了你的帖文",
|
"reblogged_post": "转发了你的帖文",
|
||||||
"request_to_follow": "请求关注你",
|
"request_to_follow": "请求关注你",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { AccountCredentials, Emoji, Instance } from 'masto'
|
import type { AccountCredentials, Emoji, Instance, Notification } from 'masto'
|
||||||
|
|
||||||
export interface AppInfo {
|
export interface AppInfo {
|
||||||
id: string
|
id: string
|
||||||
|
@ -23,3 +23,9 @@ export interface ServerInfo extends Instance {
|
||||||
timeUpdated: number
|
timeUpdated: number
|
||||||
customEmojis?: Record<string, Emoji>
|
customEmojis?: Record<string, Emoji>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GroupedNotifications {
|
||||||
|
id: string
|
||||||
|
type: string
|
||||||
|
items: Notification[]
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue