fix: chat UI
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* The unread badge on a nav entry.
|
||||
*
|
||||
* Counts threads waiting on you, not messages: one busy group shouldn't read
|
||||
* as twenty things needing attention. Muted threads are excluded server-side,
|
||||
* so muting a noisy group clears the badge while its unread count stays
|
||||
* visible in the inbox.
|
||||
*
|
||||
* Wraps its icon rather than being positioned by each caller, so the sidebar
|
||||
* and bottom bar can't drift apart.
|
||||
*/
|
||||
|
||||
import { useNotifications } from "@/components/notifications/notifications-provider";
|
||||
|
||||
export function NavUnreadBadge({ children }: { children: React.ReactNode }) {
|
||||
const { chatUnread } = useNotifications();
|
||||
if (chatUnread <= 0) return <>{children}</>;
|
||||
|
||||
return (
|
||||
<span className="relative inline-flex">
|
||||
{children}
|
||||
<span
|
||||
// Announced through the link's aria-label instead; this is decoration.
|
||||
aria-hidden
|
||||
className="absolute -right-1.5 -top-1 min-w-4 rounded-full bg-primary px-1 text-center text-[10px] font-semibold leading-4 text-white ring-2 ring-background"
|
||||
>
|
||||
{chatUnread > 9 ? "9+" : chatUnread}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
/** The count, for callers that need it in an accessible name. */
|
||||
export function useChatUnread(): number {
|
||||
return useNotifications().chatUnread;
|
||||
}
|
||||
@@ -14,6 +14,10 @@ import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { Home, MessageCircle, Search, User as UserIcon } from "lucide-react";
|
||||
import {
|
||||
NavUnreadBadge,
|
||||
useChatUnread,
|
||||
} from "@/components/layout/nav-unread-badge";
|
||||
import { useAuth } from "@/components/auth/auth-provider";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -28,6 +32,9 @@ type Item = {
|
||||
export function SiteBottomNav() {
|
||||
const pathname = usePathname();
|
||||
const { user } = useAuth();
|
||||
// Read here rather than inside the badge so the count can also reach the
|
||||
// link's accessible name — the badge itself is decorative.
|
||||
const chatUnread = useChatUnread();
|
||||
|
||||
const items: Item[] = [
|
||||
{ href: "/", label: "Home", icon: <Home className="size-5" /> },
|
||||
@@ -113,7 +120,11 @@ export function SiteBottomNav() {
|
||||
>
|
||||
<Link
|
||||
href={item.href}
|
||||
aria-label={item.label}
|
||||
aria-label={
|
||||
item.href === "/chats" && chatUnread > 0
|
||||
? `${item.label} (${chatUnread} unread)`
|
||||
: item.label
|
||||
}
|
||||
aria-current={active ? "page" : undefined}
|
||||
className={cn(
|
||||
"w-12 h-12 rounded-md flex flex-col items-center justify-center",
|
||||
@@ -122,7 +133,11 @@ export function SiteBottomNav() {
|
||||
: "text-muted-foreground hover:text-foreground",
|
||||
)}
|
||||
>
|
||||
{item.icon}
|
||||
{item.href === "/chats" ? (
|
||||
<NavUnreadBadge>{item.icon}</NavUnreadBadge>
|
||||
) : (
|
||||
item.icon
|
||||
)}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
|
||||
@@ -40,6 +40,10 @@ import {
|
||||
Settings2,
|
||||
User as UserIcon,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
NavUnreadBadge,
|
||||
useChatUnread,
|
||||
} from "@/components/layout/nav-unread-badge";
|
||||
import { useAuth } from "@/components/auth/auth-provider";
|
||||
import { ReadingSettings } from "@/components/reading-settings";
|
||||
import { KautilyaIcon } from "@/components/selection-toolbar/shared";
|
||||
@@ -177,10 +181,15 @@ function SidebarLink({
|
||||
* settings popover is up) and the mouse isn't actually hovering. */
|
||||
expandedOverride?: boolean;
|
||||
}) {
|
||||
const chatUnread = useChatUnread();
|
||||
return (
|
||||
<Link
|
||||
href={item.href}
|
||||
aria-label={item.label}
|
||||
aria-label={
|
||||
item.href === "/chats" && chatUnread > 0
|
||||
? `${item.label} (${chatUnread} unread)`
|
||||
: item.label
|
||||
}
|
||||
title={item.label}
|
||||
className={cn(
|
||||
"mx-2 h-11 flex items-center gap-3 px-3 rounded-lg overflow-hidden whitespace-nowrap text-sm font-medium",
|
||||
@@ -190,7 +199,13 @@ function SidebarLink({
|
||||
: "text-muted-foreground hover:text-foreground hover:bg-muted",
|
||||
)}
|
||||
>
|
||||
<span className="shrink-0">{item.icon}</span>
|
||||
<span className="shrink-0">
|
||||
{item.href === "/chats" ? (
|
||||
<NavUnreadBadge>{item.icon}</NavUnreadBadge>
|
||||
) : (
|
||||
item.icon
|
||||
)}
|
||||
</span>
|
||||
<span
|
||||
className={cn(
|
||||
"transition-opacity duration-150",
|
||||
|
||||
Reference in New Issue
Block a user