feat: Add direct messages (DM) support

- Parse PRIV (incoming) and SENT_MSG (outgoing) message types
- Add DM API endpoints: conversations, messages, updates
- Implement conversation grouping by pubkey_prefix or name
- Add timeout-based delivery status (pending → timeout)
- Add DM modal with conversation list and thread views
- Add dual notification badge (blue=channels, green=DM)
- Add DM button next to Reply on channel messages
- Include message deduplication for both incoming and outgoing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
MarekWo
2025-12-25 17:29:06 +01:00
parent 80e9405449
commit 1d2cc7fe18
7 changed files with 1305 additions and 5 deletions
+153
View File
@@ -329,3 +329,156 @@ main {
transform: scale(1.1);
transition: transform 0.2s ease;
}
/* =============================================================================
Direct Messages (DM) Styles
============================================================================= */
/* DM Badge on notification bell (secondary badge, bottom-right, green) */
.notification-badge-dm {
position: absolute;
bottom: -6px;
right: -6px;
background-color: #198754;
color: white;
border-radius: 8px;
padding: 1px 4px;
font-size: 0.6rem;
font-weight: bold;
min-width: 14px;
text-align: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
z-index: 10;
}
/* DM Messages Container */
.dm-messages-container {
height: 50vh;
overflow-y: auto;
padding: 0.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
background-color: #fafafa;
}
@media (max-width: 576px) {
.dm-messages-container {
height: calc(100vh - 200px);
}
}
/* DM Message Bubbles */
.dm-message {
max-width: 80%;
padding: 0.5rem 0.75rem;
border-radius: 1rem;
font-size: 0.9rem;
word-wrap: break-word;
animation: fadeIn 0.2s ease-in;
}
.dm-message.own {
align-self: flex-end;
background-color: var(--msg-own-bg);
border: 1px solid #b8daff;
}
.dm-message.other {
align-self: flex-start;
background-color: var(--msg-other-bg);
border: 1px solid var(--msg-border);
}
/* DM Message Metadata */
.dm-meta {
font-size: 0.65rem;
color: #adb5bd;
margin-top: 0.25rem;
}
/* DM Status Indicators */
.dm-status {
font-size: 0.7rem;
margin-left: 0.25rem;
}
.dm-status.pending {
color: #ffc107;
}
.dm-status.delivered {
color: #198754;
}
.dm-status.timeout {
color: #dc3545;
}
/* DM Conversation List Item */
.dm-conversation-item {
padding: 0.75rem;
border-bottom: 1px solid #dee2e6;
cursor: pointer;
transition: background-color 0.15s ease;
}
.dm-conversation-item:hover {
background-color: #f8f9fa;
}
.dm-conversation-item.unread {
background-color: #e7f1ff;
}
.dm-conversation-item:last-child {
border-bottom: none;
}
/* DM Preview Text */
.dm-preview {
font-size: 0.85rem;
color: #6c757d;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
/* DM Button on channel messages */
.btn-dm {
font-size: 0.65rem;
padding: 0.1rem 0.3rem;
margin-left: 0.25rem;
}
/* DM Empty State */
.dm-empty-state {
text-align: center;
padding: 2rem 1rem;
color: #6c757d;
}
.dm-empty-state i {
font-size: 2.5rem;
margin-bottom: 0.75rem;
opacity: 0.5;
}
/* DM Scrollbar */
.dm-messages-container::-webkit-scrollbar {
width: 6px;
}
.dm-messages-container::-webkit-scrollbar-track {
background: #f1f1f1;
}
.dm-messages-container::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 3px;
}
.dm-messages-container::-webkit-scrollbar-thumb:hover {
background: #aaa;
}