floating action pill + auto-scroll on send + channel ordering
- Actions: floating pill top-right with ↩ and × (slides in on hover) - No more ugly REPLY DEL text — minimal symbols, backdrop shadow - Delete button only shows for own messages - Auto-scroll to bottom after sending a message - Channels sorted by last opened in sidebar Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -214,7 +214,17 @@ export default function App() {
|
|||||||
channelId={activeChannelId}
|
channelId={activeChannelId}
|
||||||
replyTo={replyTo}
|
replyTo={replyTo}
|
||||||
onClearReply={() => setReplyTo(null)}
|
onClearReply={() => setReplyTo(null)}
|
||||||
onMessageSent={loadMessages}
|
onMessageSent={() => {
|
||||||
|
loadMessages();
|
||||||
|
// Force scroll to bottom after sending
|
||||||
|
setTimeout(() => {
|
||||||
|
if (scrollRef.current) {
|
||||||
|
const el = scrollRef.current as unknown as HTMLElement;
|
||||||
|
const viewport = el.querySelector('[data-slot="scroll-area-viewport"]') || el;
|
||||||
|
viewport.scrollTop = viewport.scrollHeight;
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -149,26 +149,31 @@ export function MessageItem({ message, replyTarget, onReply, onDelete, currentUs
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
|
||||||
{/* Actions */}
|
</div>
|
||||||
<div className="ml-auto flex items-center gap-1 md:opacity-0 md:group-hover:opacity-100 transition-opacity">
|
|
||||||
|
{/* Floating action pill — top-right, appears on hover */}
|
||||||
|
{!isDeleted && (
|
||||||
|
<div className="absolute -top-3 right-3 md:opacity-0 md:translate-y-1 md:group-hover:opacity-100 md:group-hover:translate-y-0 transition-all duration-150 flex border-2 border-border bg-card shadow-lg">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onReply(message.id)}
|
onClick={() => onReply(message.id)}
|
||||||
className="font-sans text-[10px] font-bold uppercase tracking-wider text-muted-foreground hover:text-primary min-w-[44px] min-h-[44px] md:min-w-0 md:min-h-0 flex items-center justify-center"
|
className="px-2 py-1 text-xs text-muted-foreground hover:text-primary hover:bg-muted/50 transition-colors"
|
||||||
|
title="Reply"
|
||||||
>
|
>
|
||||||
Reply
|
↩
|
||||||
</button>
|
</button>
|
||||||
{!isDeleted && message.user.username === currentUsername && (
|
{message.user.username === currentUsername && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onDelete(message.channel_id, message.id)}
|
onClick={() => onDelete(message.channel_id, message.id)}
|
||||||
className="font-sans text-[10px] font-bold uppercase tracking-wider text-muted-foreground hover:text-destructive min-w-[44px] min-h-[44px] md:min-w-0 md:min-h-0 flex items-center justify-center"
|
className="px-2 py-1 text-xs text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors border-l-2 border-border"
|
||||||
|
title="Delete"
|
||||||
>
|
>
|
||||||
Del
|
×
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
|
|||||||
Reference in New Issue
Block a user