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:
2026-03-29 21:25:33 +02:00
parent 36561941b4
commit 2b1ed18cde
2 changed files with 24 additions and 9 deletions

View File

@@ -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>

View File

@@ -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(