Make new message button clearer

This commit is contained in:
Jack Kingsman
2026-03-31 12:28:47 -07:00
parent b1595e479c
commit f0f06671cc
2 changed files with 69 additions and 25 deletions

View File

@@ -853,41 +853,45 @@ export function Sidebar({
aria-label="Conversations"
>
{/* Header */}
<div className="flex items-center gap-2 px-3 py-2 border-b border-border">
<div className="relative min-w-0 flex-1">
<Input
type="text"
placeholder="Search channels/contacts..."
aria-label="Search conversations"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className={cn('h-7 text-[13px] bg-background/50', searchQuery ? 'pr-8' : 'pr-3')}
/>
{searchQuery && (
<button
className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground text-lg leading-none transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded"
onClick={() => setSearchQuery('')}
title="Clear search"
aria-label="Clear search"
>
<X className="h-4 w-4" />
</button>
)}
</div>
<div className="px-3 py-2 border-b border-border">
<Button
variant="ghost"
variant="outline"
size="sm"
onClick={onNewMessage}
title="New Message"
aria-label="New message"
className="h-7 w-7 shrink-0 p-0 text-muted-foreground hover:text-foreground transition-colors"
title="Add channel or contact"
aria-label="Add channel or contact"
className="h-8 w-full justify-start gap-2 px-3 text-[13px]"
>
<SquarePen className="h-4 w-4" />
<span>Add Channel/Contact</span>
</Button>
</div>
{/* List */}
<div className="flex-1 min-h-0 overflow-y-auto [contain:layout_paint]">
<div className="px-3 py-2 border-b border-border/60">
<div className="relative min-w-0">
<Input
type="text"
placeholder="Search channels/contacts..."
aria-label="Search conversations"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className={cn('h-7 text-[13px] bg-background/50', searchQuery ? 'pr-8' : 'pr-3')}
/>
{searchQuery && (
<button
className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground text-lg leading-none transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded"
onClick={() => setSearchQuery('')}
title="Clear search"
aria-label="Clear search"
>
<X className="h-4 w-4" />
</button>
)}
</div>
</div>
{/* Tools */}
{toolRows.length > 0 && (
<>

View File

@@ -122,6 +122,46 @@ describe('Sidebar section summaries', () => {
expect(within(getSectionHeaderContainer('Repeaters')).getByText('4')).toBeInTheDocument();
});
it('renders a full add channel/contact button above search and calls onNewMessage', () => {
const onNewMessage = vi.fn();
render(
<Sidebar
contacts={[]}
channels={[makeChannel(PUBLIC_CHANNEL_KEY, 'Public')]}
activeConversation={null}
onSelectConversation={vi.fn()}
onNewMessage={onNewMessage}
lastMessageTimes={{}}
unreadCounts={{}}
mentions={{}}
showCracker={false}
crackerRunning={false}
onToggleCracker={vi.fn()}
onMarkAllRead={vi.fn()}
favorites={[]}
legacySortOrder="recent"
/>
);
const addButton = screen.getByRole('button', { name: 'Add channel or contact' });
const search = screen.getByLabelText('Search conversations');
const nav = screen.getByRole('navigation', { name: 'Conversations' });
const toolsButton = screen.getByRole('button', { name: 'Tools' });
expect(addButton).toHaveTextContent('Add Channel/Contact');
expect(
addButton.compareDocumentPosition(search) & Node.DOCUMENT_POSITION_FOLLOWING
).toBeTruthy();
expect(nav.compareDocumentPosition(search) & Node.DOCUMENT_POSITION_CONTAINED_BY).toBeTruthy();
expect(
search.compareDocumentPosition(toolsButton) & Node.DOCUMENT_POSITION_FOLLOWING
).toBeTruthy();
fireEvent.click(addButton);
expect(onNewMessage).toHaveBeenCalledTimes(1);
});
it('turns favorites and channels rollups red when they contain a mention', () => {
renderSidebar({
mentions: {