Skip to content

Commit f240930

Browse files
authored
Merge pull request #277 from codeunia-dev/ui/messaging
feat(messages): Improve messaging UI with enhanced layout and dark mode support
2 parents 2a7bf22 + 20edf17 commit f240930

File tree

6 files changed

+67
-45
lines changed

6 files changed

+67
-45
lines changed

app/protected/messages/page.tsx

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ export default function MessagesPage() {
2222
// Track user's online presence
2323
useMyPresence()
2424

25+
// Prevent body scroll
26+
useEffect(() => {
27+
document.body.style.overflow = 'hidden'
28+
return () => {
29+
document.body.style.overflow = 'unset'
30+
}
31+
}, [])
32+
2533
// Get conversation from URL params
2634
useEffect(() => {
2735
const conversationId = searchParams.get('conversation')
@@ -53,15 +61,20 @@ export default function MessagesPage() {
5361
: 'Unknown'
5462

5563
return (
56-
<div className="flex flex-col h-[calc(100vh-4rem)]">
64+
<div className="flex flex-col h-[100dvh] bg-black overflow-hidden absolute inset-0">
5765
{/* Header */}
58-
<div className="border-b bg-background p-4">
66+
<div className="border-b border-zinc-800 bg-black p-4 flex-shrink-0">
5967
<div className="max-w-7xl mx-auto flex items-center justify-between">
6068
<div className="flex items-center gap-3">
61-
<MessageSquare className="h-6 w-6 text-primary" />
62-
<h1 className="text-xl md:text-2xl font-bold">Messages</h1>
69+
<div className="p-2 rounded-lg bg-gradient-to-br from-blue-500 to-purple-600">
70+
<MessageSquare className="h-5 w-5 text-white" />
71+
</div>
72+
<h1 className="text-xl md:text-2xl font-bold text-white">Messages</h1>
6373
</div>
64-
<Button onClick={() => setShowNewMessage(true)} className="gap-2">
74+
<Button
75+
onClick={() => setShowNewMessage(true)}
76+
className="gap-2 bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white border-0"
77+
>
6578
<Plus className="h-4 w-4" />
6679
<span className="hidden sm:inline">New Message</span>
6780
<span className="sm:hidden">New</span>
@@ -74,18 +87,18 @@ export default function MessagesPage() {
7487
<div className="max-w-7xl mx-auto h-full flex">
7588
{/* Sidebar - Conversation List (Hidden on mobile when conversation is selected) */}
7689
<div className={`
77-
w-full md:w-80 md:border-r flex flex-col bg-background
90+
w-full md:w-80 md:border-r md:border-zinc-800 flex flex-col bg-black
7891
${selectedConversationId ? 'hidden md:flex' : 'flex'}
7992
`}>
8093
{/* Search */}
81-
<div className="p-3 border-b">
94+
<div className="p-3 border-b border-zinc-800">
8295
<div className="relative">
83-
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
96+
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-zinc-500" />
8497
<Input
8598
placeholder="Search conversations..."
8699
value={searchQuery}
87100
onChange={(e) => setSearchQuery(e.target.value)}
88-
className="pl-9"
101+
className="pl-9 bg-zinc-900 border-zinc-800 text-white placeholder:text-zinc-500 focus:border-blue-500 focus:ring-blue-500"
89102
/>
90103
</div>
91104
</div>
@@ -103,17 +116,17 @@ export default function MessagesPage() {
103116

104117
{/* Main Area - Conversation View (Hidden on mobile when no conversation selected) */}
105118
<div className={`
106-
flex-1 bg-background flex flex-col
119+
flex-1 bg-black flex flex-col
107120
${selectedConversationId ? 'flex' : 'hidden md:flex'}
108121
`}>
109122
{selectedConversationId && selectedConversation && (
110-
<div className="border-b p-3 md:p-4 bg-muted/50 flex-shrink-0">
123+
<div className="border-b border-zinc-800 p-3 md:p-4 bg-zinc-900/50 flex-shrink-0">
111124
<div className="flex items-center gap-2 md:gap-3">
112125
{/* Back button for mobile */}
113126
<Button
114127
variant="ghost"
115128
size="icon"
116-
className="md:hidden"
129+
className="md:hidden text-white hover:bg-zinc-800"
117130
onClick={() => setSelectedConversationId(null)}
118131
>
119132
<svg
@@ -130,7 +143,7 @@ export default function MessagesPage() {
130143
<path d="m15 18-6-6 6-6"/>
131144
</svg>
132145
</Button>
133-
<h2 className="font-semibold text-sm md:text-base truncate">{conversationName}</h2>
146+
<h2 className="font-semibold text-sm md:text-base truncate text-white">{conversationName}</h2>
134147
{!selectedConversation.is_group && selectedConversation.other_user && selectedConversation.other_user.id ? (
135148
<UserStatusIndicator
136149
userId={selectedConversation.other_user.id}

components/messages/ConversationList.tsx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@ export function ConversationList({ conversations, selectedId, onSelect, loading
5151
if (conversations.length === 0) {
5252
return (
5353
<div className="flex flex-col items-center justify-center h-full p-8 text-center">
54-
<MessageCircle className="h-12 w-12 text-muted-foreground mb-4" />
55-
<h3 className="text-lg font-semibold mb-2">No conversations yet</h3>
56-
<p className="text-sm text-muted-foreground">
54+
<div className="p-4 rounded-full bg-zinc-900 mb-4">
55+
<MessageCircle className="h-12 w-12 text-zinc-600" />
56+
</div>
57+
<h3 className="text-lg font-semibold mb-2 text-white">No conversations yet</h3>
58+
<p className="text-sm text-zinc-400">
5759
Start a new conversation to get started
5860
</p>
5961
</div>
@@ -87,13 +89,13 @@ export function ConversationList({ conversations, selectedId, onSelect, loading
8789
key={conversation.id}
8890
onClick={() => onSelect(conversation.id)}
8991
className={cn(
90-
'w-full flex items-center gap-3 p-3 rounded-lg transition-colors text-left',
91-
'hover:bg-muted',
92-
isSelected && 'bg-muted'
92+
'w-full flex items-center gap-3 p-3 rounded-lg transition-all text-left',
93+
'hover:bg-zinc-900',
94+
isSelected && 'bg-zinc-900 border border-zinc-800'
9395
)}
9496
>
9597
<div className="relative">
96-
<Avatar className="w-12 h-12 flex-shrink-0">
98+
<Avatar className="w-12 h-12 flex-shrink-0 ring-2 ring-zinc-800">
9799
{avatarUrl && <AvatarImage src={avatarUrl} alt={name} />}
98100
<AvatarFallback className="bg-gradient-to-br from-blue-500 to-purple-600 text-white">
99101
{initials}
@@ -111,24 +113,27 @@ export function ConversationList({ conversations, selectedId, onSelect, loading
111113

112114
<div className="flex-1 min-w-0">
113115
<div className="flex items-center justify-between mb-1">
114-
<span className={cn('font-semibold truncate text-sm md:text-base', conversation.unread_count > 0 && 'text-primary')}>
116+
<span className={cn(
117+
'font-semibold truncate text-sm md:text-base',
118+
conversation.unread_count > 0 ? 'text-blue-400' : 'text-white'
119+
)}>
115120
{name}
116121
</span>
117122
{conversation.last_message_at && (
118-
<span className="text-[10px] md:text-xs text-muted-foreground flex-shrink-0 ml-2">
123+
<span className="text-[10px] md:text-xs text-zinc-500 flex-shrink-0 ml-2">
119124
{formatDistanceToNow(new Date(conversation.last_message_at), { addSuffix: true })}
120125
</span>
121126
)}
122127
</div>
123128
<div className="flex items-center justify-between">
124129
<p className={cn(
125130
'text-xs md:text-sm truncate',
126-
conversation.unread_count > 0 ? 'font-medium text-foreground' : 'text-muted-foreground'
131+
conversation.unread_count > 0 ? 'font-medium text-zinc-300' : 'text-zinc-500'
127132
)}>
128133
{conversation.last_message_content || 'No messages yet'}
129134
</p>
130135
{conversation.unread_count > 0 && (
131-
<Badge variant="default" className="ml-2 flex-shrink-0 text-xs">
136+
<Badge className="ml-2 flex-shrink-0 text-xs bg-gradient-to-r from-blue-500 to-purple-600 text-white border-0">
132137
{conversation.unread_count}
133138
</Badge>
134139
)}

components/messages/ConversationView.tsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ export function ConversationView({ conversationId }: ConversationViewProps) {
2828

2929
if (!conversationId) {
3030
return (
31-
<div className="h-full flex flex-col items-center justify-center p-8 text-center">
32-
<MessageSquare className="h-16 w-16 text-muted-foreground mb-4" />
33-
<h3 className="text-xl font-semibold mb-2">Select a conversation</h3>
34-
<p className="text-muted-foreground">
31+
<div className="h-full flex flex-col items-center justify-center p-8 text-center bg-black">
32+
<div className="p-6 rounded-full bg-zinc-900 mb-6">
33+
<MessageSquare className="h-16 w-16 text-zinc-600" />
34+
</div>
35+
<h3 className="text-xl font-semibold mb-2 text-white">Select a conversation</h3>
36+
<p className="text-zinc-400">
3537
Choose a conversation from the list to start messaging
3638
</p>
3739
</div>
@@ -57,14 +59,16 @@ export function ConversationView({ conversationId }: ConversationViewProps) {
5759
}
5860

5961
return (
60-
<div className="h-full flex flex-col">
62+
<div className="h-full flex flex-col bg-black">
6163
{/* Messages Area */}
6264
<div className="flex-1 overflow-y-auto p-4 min-h-0">
6365
{messages.length === 0 ? (
6466
<div className="flex flex-col items-center justify-center h-full text-center">
65-
<MessageSquare className="h-12 w-12 text-muted-foreground mb-4" />
66-
<h3 className="text-lg font-semibold mb-2">No messages yet</h3>
67-
<p className="text-sm text-muted-foreground">
67+
<div className="p-4 rounded-full bg-zinc-900 mb-4">
68+
<MessageSquare className="h-12 w-12 text-zinc-600" />
69+
</div>
70+
<h3 className="text-lg font-semibold mb-2 text-white">No messages yet</h3>
71+
<p className="text-sm text-zinc-400">
6872
Send a message to start the conversation
6973
</p>
7074
</div>
@@ -88,7 +92,7 @@ export function ConversationView({ conversationId }: ConversationViewProps) {
8892
)}
8993

9094
{/* Message Input */}
91-
<div className="flex-shrink-0">
95+
<div className="flex-shrink-0 border-t border-zinc-800">
9296
<MessageInput
9397
onSend={sendMessage}
9498
disabled={sending}

components/messages/MessageBubble.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@ export function MessageBubble({ message, isOwn }: MessageBubbleProps) {
3939

4040
<div className={cn('flex flex-col', isOwn ? 'items-end' : 'items-start', 'max-w-[70%]')}>
4141
{!isOwn && (
42-
<span className="text-xs font-medium text-muted-foreground mb-1">
42+
<span className="text-xs font-medium text-zinc-400 mb-1">
4343
{getName()}
4444
</span>
4545
)}
4646

4747
<div
4848
className={cn(
49-
'rounded-2xl px-4 py-2 break-words',
49+
'rounded-2xl px-4 py-2 break-words shadow-lg',
5050
isOwn
5151
? 'bg-gradient-to-br from-blue-500 to-purple-600 text-white'
52-
: 'bg-muted text-foreground',
52+
: 'bg-zinc-900 text-white border border-zinc-800',
5353
message.is_deleted && 'italic opacity-60'
5454
)}
5555
>
@@ -59,7 +59,7 @@ export function MessageBubble({ message, isOwn }: MessageBubbleProps) {
5959
)}
6060
</div>
6161

62-
<span className="text-xs text-muted-foreground mt-1">
62+
<span className="text-xs text-zinc-500 mt-1">
6363
{formatDistanceToNow(new Date(message.created_at), { addSuffix: true })}
6464
</span>
6565
</div>

components/messages/MessageInput.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export function MessageInput({ onSend, disabled, placeholder = 'Type a message..
9090
}, [content, isTyping, onTyping])
9191

9292
return (
93-
<form onSubmit={handleSubmit} className="border-t bg-background p-2 md:p-3">
93+
<form onSubmit={handleSubmit} className="bg-black p-3 md:p-4">
9494
<div className="flex gap-2 items-end max-w-full">
9595
<Textarea
9696
ref={textareaRef}
@@ -99,14 +99,14 @@ export function MessageInput({ onSend, disabled, placeholder = 'Type a message..
9999
onKeyDown={handleKeyDown}
100100
placeholder={placeholder}
101101
disabled={disabled || sending}
102-
className="min-h-[40px] md:min-h-[44px] max-h-[120px] resize-none flex-1 text-sm md:text-base"
102+
className="min-h-[40px] md:min-h-[44px] max-h-[120px] resize-none flex-1 text-sm md:text-base bg-zinc-900 border-zinc-800 text-white placeholder:text-zinc-500 focus:border-blue-500 focus:ring-blue-500"
103103
rows={1}
104104
/>
105105
<Button
106106
type="submit"
107107
size="icon"
108108
disabled={!content.trim() || sending || disabled}
109-
className="flex-shrink-0 h-10 w-10 md:h-11 md:w-11"
109+
className="flex-shrink-0 h-10 w-10 md:h-11 md:w-11 bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white border-0"
110110
>
111111
{sending ? (
112112
<Loader2 className="h-4 w-4 animate-spin" />
@@ -115,7 +115,7 @@ export function MessageInput({ onSend, disabled, placeholder = 'Type a message..
115115
)}
116116
</Button>
117117
</div>
118-
<p className="text-[10px] md:text-xs text-muted-foreground mt-1 md:mt-1.5 hidden sm:block">
118+
<p className="text-[10px] md:text-xs text-zinc-500 mt-1.5 hidden sm:block">
119119
Press Enter to send, Shift+Enter for new line
120120
</p>
121121
</form>

components/messages/TypingIndicator.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ export function TypingIndicator({ usernames }: TypingIndicatorProps) {
1010
if (usernames.length === 0) return null
1111

1212
return (
13-
<div className="flex items-center gap-2 px-4 py-2 text-sm text-muted-foreground">
13+
<div className="flex items-center gap-2 px-4 py-2 text-sm text-zinc-400 bg-black">
1414
<div className="flex gap-1">
15-
<span className="w-2 h-2 bg-muted-foreground rounded-full animate-bounce" style={{ animationDelay: '0ms' }} />
16-
<span className="w-2 h-2 bg-muted-foreground rounded-full animate-bounce" style={{ animationDelay: '150ms' }} />
17-
<span className="w-2 h-2 bg-muted-foreground rounded-full animate-bounce" style={{ animationDelay: '300ms' }} />
15+
<span className="w-2 h-2 bg-blue-500 rounded-full animate-bounce" style={{ animationDelay: '0ms' }} />
16+
<span className="w-2 h-2 bg-purple-500 rounded-full animate-bounce" style={{ animationDelay: '150ms' }} />
17+
<span className="w-2 h-2 bg-blue-500 rounded-full animate-bounce" style={{ animationDelay: '300ms' }} />
1818
</div>
1919
<span>Typing...</span>
2020
</div>

0 commit comments

Comments
 (0)