Grouped favourite+boost notifications!

This commit is contained in:
Lim Chee Aun 2023-03-03 11:38:10 +08:00
parent e7dc2c8517
commit 7b8c7f3fb6
3 changed files with 122 additions and 23 deletions

View file

@ -1258,13 +1258,13 @@ meter.donut:is(.danger, .explode):after {
} }
/* I'm just feeling bored, so having fun here */ /* I'm just feeling bored, so having fun here */
@media (hover: hover) { @media (hover: hover) {
.avatars-stack > * { .avatars-stack > * img {
transition: transform 0.3s ease-in-out; transition: transform 0.3s ease-in-out;
} }
.avatars-stack:hover > *:nth-of-type(odd) { .avatars-stack:hover > *:nth-of-type(odd) img {
transform: rotate(15deg); transform: rotate(15deg);
} }
.avatars-stack:hover > *:nth-of-type(even) { .avatars-stack:hover > *:nth-of-type(even) img {
transform: rotate(-15deg); transform: rotate(-15deg);
} }
} }

View file

@ -20,6 +20,7 @@
flex-shrink: 0; flex-shrink: 0;
opacity: 0.75; opacity: 0.75;
color: var(--text-insignificant-color); color: var(--text-insignificant-color);
line-height: 0;
} }
.notification-type.notification-mention { .notification-type.notification-mention {
color: var(--reply-to-color); color: var(--reply-to-color);
@ -34,6 +35,54 @@
color: var(--link-color); color: var(--link-color);
} }
.notification .reblog-icon {
color: var(--reblog-color);
}
.notification .favourite-icon {
color: var(--favourite-color);
}
.notification .account-avatar-stack {
position: relative;
text-align: center;
}
.notification .account-avatar-stack .account-sub-icons {
display: block;
width: fit-content;
margin: -0.25em auto 0;
line-height: 1;
background-color: var(--bg-blur-color);
/* background-image: linear-gradient(
to bottom,
var(--bg-color),
var(--bg-blur-color)
); */
backdrop-filter: blur(16px) saturate(3);
padding: 2px 4px;
border-radius: 999px;
overflow: hidden;
border: var(--hairline-width) solid var(--bg-color);
box-shadow: 0 1px var(--drop-shadow-color);
}
.notification .avatars-stack .account-avatar-stack .account-sub-icons .icon {
transition: transform 0.2s ease-out;
}
.notification
.avatars-stack:hover
.account-avatar-stack
.account-sub-icons
.icon {
transform: rotate(-15deg);
}
.notification
.avatars-stack:hover
.account-avatar-stack
.account-sub-icons
.icon
+ .icon {
transform: rotate(15deg);
}
.notification .status-link { .notification .status-link {
border-radius: 8px; border-radius: 8px;
border: 1px solid var(--outline-color); border: 1px solid var(--outline-color);

View file

@ -45,6 +45,18 @@ const contentText = {
'poll-self': 'A poll you have created has ended.', 'poll-self': 'A poll you have created has ended.',
'poll-voted': 'A poll you have voted in has ended.', 'poll-voted': 'A poll you have voted in has ended.',
update: 'A status you interacted with has been edited.', update: 'A status you interacted with has been edited.',
'favourite+reblog': 'boosted & favourited your status.',
};
const NOTIFICATION_ICONS = {
mention: 'comment',
status: 'notification',
reblog: 'rocket',
follow: 'follow',
follow_request: 'follow-add',
favourite: 'heart',
poll: 'poll',
update: 'pencil',
}; };
const LIMIT = 30; // 30 is the maximum limit :( const LIMIT = 30; // 30 is the maximum limit :(
@ -275,7 +287,8 @@ function Notifications() {
); );
} }
function Notification({ notification, instance }) { function Notification({ notification, instance }) {
const { id, type, status, account, _accounts } = notification; const { id, status, account, _accounts } = notification;
let { type } = notification;
// status = Attached when type of the notification is favourite, reblog, status, mention, poll, or update // status = Attached when type of the notification is favourite, reblog, status, mention, poll, or update
const actualStatusID = status?.reblog?.id || status?.id; const actualStatusID = status?.reblog?.id || status?.id;
@ -284,6 +297,20 @@ function Notification({ notification, instance }) {
const isSelf = currentAccount === account?.id; const isSelf = currentAccount === account?.id;
const isVoted = status?.poll?.voted; const isVoted = status?.poll?.voted;
let favsCount = 0;
let reblogsCount = 0;
if (type === 'favourite+reblog') {
for (const account of _accounts) {
if (account._types?.includes('favourite')) {
favsCount++;
} else if (account._types?.includes('reblog')) {
reblogsCount++;
}
}
if (!reblogsCount && favsCount) type = 'favourite';
if (!favsCount && reblogsCount) type = 'reblog';
}
const text = const text =
type === 'poll' type === 'poll'
? contentText[isSelf ? 'poll-self' : isVoted ? 'poll-voted' : 'poll'] ? contentText[isSelf ? 'poll-self' : isVoted ? 'poll-voted' : 'poll']
@ -295,22 +322,18 @@ function Notification({ notification, instance }) {
class={`notification-type notification-${type}`} class={`notification-type notification-${type}`}
title={new Date(notification.createdAt).toLocaleString()} title={new Date(notification.createdAt).toLocaleString()}
> >
<Icon {type === 'favourite+reblog' ? (
icon={ <>
{ <Icon icon="rocket" size="xl" alt={type} class="reblog-icon" />
mention: 'comment', <Icon icon="heart" size="xl" alt={type} class="favourite-icon" />
status: 'notification', </>
reblog: 'rocket', ) : (
follow: 'follow', <Icon
follow_request: 'follow-add', icon={NOTIFICATION_ICONS[type] || 'notification'}
favourite: 'heart', size="xl"
poll: 'poll', alt={type}
update: 'pencil', />
}[type] || 'notification' )}
}
size="xl"
alt={type}
/>
</div> </div>
<div class="notification-content"> <div class="notification-content">
{type !== 'mention' && ( {type !== 'mention' && (
@ -358,6 +381,7 @@ function Notification({ notification, instance }) {
<a <a
href={account.url} href={account.url}
rel="noopener noreferrer" rel="noopener noreferrer"
class="account-avatar-stack"
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
states.showAccount = account; states.showAccount = account;
@ -379,6 +403,17 @@ function Notification({ notification, instance }) {
key={account.id} key={account.id}
alt={`${account.displayName} @${account.acct}`} alt={`${account.displayName} @${account.acct}`}
/> />
{type === 'favourite+reblog' && (
<div class="account-sub-icons">
{account._types.map((type) => (
<Icon
icon={NOTIFICATION_ICONS[type]}
size="s"
class={`${type}-icon`}
/>
))}
</div>
)}
</a>{' '} </a>{' '}
</> </>
))} ))}
@ -458,15 +493,30 @@ function groupNotifications(notifications) {
const notification = notifications[i]; const notification = notifications[i];
const { status, account, type, createdAt } = notification; const { status, account, type, createdAt } = notification;
const date = new Date(createdAt).toLocaleDateString(); const date = new Date(createdAt).toLocaleDateString();
const key = `${status?.id}-${type}-${date}`; let virtualType = type;
if (type === 'favourite' || type === 'reblog') {
virtualType = 'favourite+reblog';
}
const key = `${status?.id}-${virtualType}-${date}`;
const mappedNotification = notificationsMap[key]; const mappedNotification = notificationsMap[key];
if (type === 'follow_request') { if (virtualType === 'follow_request') {
cleanNotifications[j++] = notification; cleanNotifications[j++] = notification;
} else if (mappedNotification?.account) { } else if (mappedNotification?.account) {
mappedNotification._accounts.push(account); const mappedAccount = mappedNotification._accounts.find(
(a) => a.id === account.id,
);
if (mappedAccount) {
mappedAccount._types.push(type);
mappedAccount._types.sort().reverse();
} else {
account._types = [type];
mappedNotification._accounts.push(account);
}
} else { } else {
account._types = [type];
let n = (notificationsMap[key] = { let n = (notificationsMap[key] = {
...notification, ...notification,
type: virtualType,
_accounts: [account], _accounts: [account],
}); });
cleanNotifications[j++] = n; cleanNotifications[j++] = n;