notifications

This commit is contained in:
alma 2025-05-04 12:18:34 +02:00
parent 9b62063962
commit 3275b8b6c9
5 changed files with 70 additions and 3 deletions

View File

@ -74,6 +74,38 @@
} }
} }
/* Notification message styles */
.notification-message {
max-width: 100%;
word-wrap: break-word;
line-height: 1.4;
}
.notification-message p {
margin: 0.25rem 0;
}
.notification-message img {
max-width: 16px;
height: 16px;
display: inline-block;
vertical-align: middle;
border-radius: 50%;
margin-right: 4px;
}
.notification-message a.userMention {
font-weight: 500;
color: #3b82f6;
text-decoration: none;
display: inline-flex;
align-items: center;
}
.notification-message a:hover {
text-decoration: underline;
}
/* Email display styles */ /* Email display styles */
.email-content-display { .email-content-display {
max-width: 100%; max-width: 100%;

View File

@ -13,6 +13,7 @@ import {
DropdownMenuSeparator, DropdownMenuSeparator,
} from '@/components/ui/dropdown-menu'; } from '@/components/ui/dropdown-menu';
import { formatDistanceToNow } from 'date-fns'; import { formatDistanceToNow } from 'date-fns';
import { SafeHTML } from '@/components/safe-html';
interface NotificationBadgeProps { interface NotificationBadgeProps {
className?: string; className?: string;
@ -168,7 +169,7 @@ export const NotificationBadge = memo(function NotificationBadge({ className }:
<DropdownMenuItem key={notification.id} className="px-4 py-3 cursor-default"> <DropdownMenuItem key={notification.id} className="px-4 py-3 cursor-default">
<div className="w-full"> <div className="w-full">
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div> <div className="max-w-[90%]">
<p className="text-sm font-medium"> <p className="text-sm font-medium">
{notification.title} {notification.title}
{!notification.isRead && ( {!notification.isRead && (
@ -179,7 +180,7 @@ export const NotificationBadge = memo(function NotificationBadge({ className }:
{formatDistanceToNow(new Date(notification.timestamp), { addSuffix: true })} {formatDistanceToNow(new Date(notification.timestamp), { addSuffix: true })}
</p> </p>
</div> </div>
<div className="flex space-x-1"> <div className="flex space-x-1 ml-2">
{!notification.isRead && ( {!notification.isRead && (
<Button <Button
variant="ghost" variant="ghost"
@ -201,7 +202,10 @@ export const NotificationBadge = memo(function NotificationBadge({ className }:
)} )}
</div> </div>
</div> </div>
<p className="text-xs mt-1">{notification.message}</p> <SafeHTML
html={notification.message}
className="text-xs mt-1 notification-message"
/>
</div> </div>
</DropdownMenuItem> </DropdownMenuItem>
))} ))}

29
components/safe-html.tsx Normal file
View File

@ -0,0 +1,29 @@
import React from 'react';
import DOMPurify from 'dompurify';
interface SafeHTMLProps {
html: string;
className?: string;
}
export function SafeHTML({ html, className }: SafeHTMLProps) {
const sanitizedHTML = DOMPurify.sanitize(html, {
USE_PROFILES: { html: true },
ALLOWED_TAGS: [
'a', 'p', 'br', 'b', 'i', 'em', 'strong', 'span', 'div',
'img', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'code', 'pre', 'blockquote'
],
ALLOWED_ATTR: [
'href', 'target', 'class', 'id', 'style', 'src', 'alt',
'data-tagged-user-id', 'data-mention'
]
});
return (
<div
className={className}
dangerouslySetInnerHTML={{ __html: sanitizedHTML }}
/>
);
}

1
package-lock.json generated
View File

@ -57,6 +57,7 @@
"cookies-next": "^5.1.0", "cookies-next": "^5.1.0",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
"dompurify": "^3.2.5",
"dotenv": "^16.5.0", "dotenv": "^16.5.0",
"embla-carousel-react": "8.5.1", "embla-carousel-react": "8.5.1",
"fullcalendar": "^6.1.15", "fullcalendar": "^6.1.15",

View File

@ -58,6 +58,7 @@
"cookies-next": "^5.1.0", "cookies-next": "^5.1.0",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
"dompurify": "^3.2.5",
"dotenv": "^16.5.0", "dotenv": "^16.5.0",
"embla-carousel-react": "8.5.1", "embla-carousel-react": "8.5.1",
"fullcalendar": "^6.1.15", "fullcalendar": "^6.1.15",