notifications
This commit is contained in:
parent
9b62063962
commit
3275b8b6c9
@ -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-content-display {
|
||||
max-width: 100%;
|
||||
|
||||
@ -13,6 +13,7 @@ import {
|
||||
DropdownMenuSeparator,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { SafeHTML } from '@/components/safe-html';
|
||||
|
||||
interface NotificationBadgeProps {
|
||||
className?: string;
|
||||
@ -168,7 +169,7 @@ export const NotificationBadge = memo(function NotificationBadge({ className }:
|
||||
<DropdownMenuItem key={notification.id} className="px-4 py-3 cursor-default">
|
||||
<div className="w-full">
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<div className="max-w-[90%]">
|
||||
<p className="text-sm font-medium">
|
||||
{notification.title}
|
||||
{!notification.isRead && (
|
||||
@ -179,7 +180,7 @@ export const NotificationBadge = memo(function NotificationBadge({ className }:
|
||||
{formatDistanceToNow(new Date(notification.timestamp), { addSuffix: true })}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex space-x-1">
|
||||
<div className="flex space-x-1 ml-2">
|
||||
{!notification.isRead && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
@ -201,7 +202,10 @@ export const NotificationBadge = memo(function NotificationBadge({ className }:
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs mt-1">{notification.message}</p>
|
||||
<SafeHTML
|
||||
html={notification.message}
|
||||
className="text-xs mt-1 notification-message"
|
||||
/>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
|
||||
29
components/safe-html.tsx
Normal file
29
components/safe-html.tsx
Normal 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
1
package-lock.json
generated
@ -57,6 +57,7 @@
|
||||
"cookies-next": "^5.1.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"dompurify": "^3.2.5",
|
||||
"dotenv": "^16.5.0",
|
||||
"embla-carousel-react": "8.5.1",
|
||||
"fullcalendar": "^6.1.15",
|
||||
|
||||
@ -58,6 +58,7 @@
|
||||
"cookies-next": "^5.1.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"dompurify": "^3.2.5",
|
||||
"dotenv": "^16.5.0",
|
||||
"embla-carousel-react": "8.5.1",
|
||||
"fullcalendar": "^6.1.15",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user