diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json
index 278021657..a182138ac 100644
--- a/apps/client/public/locales/en-US/translation.json
+++ b/apps/client/public/locales/en-US/translation.json
@@ -978,7 +978,7 @@
"Search pages and spaces...": "Search pages and spaces...",
"No results found": "No results found",
"You don't have permission to create pages here": "You don't have permission to create pages here",
- "Chat menu": "Chat menu",
+ "Chat menu for {{title}}": "Chat menu for {{title}}",
"API key menu": "API key menu",
"Jump to comment selection": "Jump to comment selection",
"Slash commands": "Slash commands",
@@ -1064,7 +1064,7 @@
"Filter": "Filter",
"Page title": "Page title",
"Page content": "Page content",
- "Member actions": "Member actions",
+ "Member actions for {{name}}": "Member actions for {{name}}",
"Toggle password visibility": "Toggle password visibility",
"Send comment": "Send comment",
"Token actions": "Token actions",
diff --git a/apps/client/src/components/layouts/global/global-sidebar.tsx b/apps/client/src/components/layouts/global/global-sidebar.tsx
index 4670dae40..5ec322a58 100644
--- a/apps/client/src/components/layouts/global/global-sidebar.tsx
+++ b/apps/client/src/components/layouts/global/global-sidebar.tsx
@@ -105,7 +105,7 @@ export default function GlobalSidebar() {
-
{t("Favorite spaces")}
+
{t("Favorite spaces")}
{!isFavoritesPending && sortedFavoriteSpaces.length === 0 ? (
{t("Favorite spaces appear here")}
diff --git a/apps/client/src/components/ui/custom-avatar.tsx b/apps/client/src/components/ui/custom-avatar.tsx
index 0cf20a51b..c708b1769 100644
--- a/apps/client/src/components/ui/custom-avatar.tsx
+++ b/apps/client/src/components/ui/custom-avatar.tsx
@@ -16,13 +16,10 @@ interface CustomAvatarProps {
mt?: string | number;
}
-// `color.shade` pairs whose contrast meets WCAG AA (4.5:1) in BOTH variants:
-// - filled: white text on the shade as bg
-// - light: shade as text on the color's light-bg (10% color.6 over white)
-// Avoids lime/yellow/green/orange — even their dark shades have weak
-// contrast. grape and indigo were bumped from .7 to darker shades because
-// the original picks failed: grape.7 was 4.02/3.61 (both fail) and
-// indigo.7 was 4.98/4.39 (light fails by a hair).
+// color.shade picks whose FILLED variant (white text on the shade) meets WCAG AA 4.5:1.
+// Avoids lime/yellow/green/orange, too light even at dark shades.
+// For non-filled variants, initials text is forced to the .9 shade at render time:
+// Mantine otherwise caps light-variant placeholder text at .6, dropping contrast to ~3:1.
const SAFE_INITIALS_COLORS: MantineColor[] = [
"blue.8",
"cyan.9",
@@ -54,12 +51,21 @@ function sanitizeInitialsSource(name: string) {
export const CustomAvatar = React.forwardRef<
HTMLInputElement,
CustomAvatarProps
->(({ avatarUrl, name, type, color, ...props }: CustomAvatarProps, ref) => {
+>(({ avatarUrl, name, type, color, variant, ...props }: CustomAvatarProps, ref) => {
const avatarLink = getAvatarUrl(avatarUrl, type);
- const resolvedColor =
- !color || color === "initials" ? pickInitialsColor(name ?? "") : color;
+ const isInitials = !color || color === "initials";
+ const resolvedColor = isInitials ? pickInitialsColor(name ?? "") : color;
const initialsSource = sanitizeInitialsSource(name ?? "");
+ const placeholderStyles =
+ isInitials && variant !== "filled"
+ ? {
+ placeholder: {
+ color: `var(--mantine-color-${resolvedColor.split(".")[0]}-9)`,
+ },
+ }
+ : undefined;
+
return (
);
diff --git a/apps/client/src/components/ui/radio-menu-item.tsx b/apps/client/src/components/ui/radio-menu-item.tsx
new file mode 100644
index 000000000..3f0ae7c8f
--- /dev/null
+++ b/apps/client/src/components/ui/radio-menu-item.tsx
@@ -0,0 +1,12 @@
+import { UnstyledButton } from "@mantine/core";
+import { type ComponentPropsWithoutRef, forwardRef } from "react";
+
+// Menu.Item hard-codes role="menuitem"; use as its `component` to restore role="menuitemradio" so aria-checked works.
+export const RadioMenuItem = forwardRef<
+ HTMLButtonElement,
+ ComponentPropsWithoutRef<"button">
+>((props, ref) => (
+
+));
+
+RadioMenuItem.displayName = "RadioMenuItem";
diff --git a/apps/client/src/ee/ai-chat/components/ai-chat-sidebar-item.tsx b/apps/client/src/ee/ai-chat/components/ai-chat-sidebar-item.tsx
index e2bd553c8..4f3d32af3 100644
--- a/apps/client/src/ee/ai-chat/components/ai-chat-sidebar-item.tsx
+++ b/apps/client/src/ee/ai-chat/components/ai-chat-sidebar-item.tsx
@@ -66,6 +66,8 @@ export default function AiChatSidebarItem({
[chat.updatedAt, i18n.language],
);
+ const chatTitle = chat.title || t("Untitled chat");
+
useEffect(() => {
if (renaming) {
// Wait for the input to be mounted before selecting.
@@ -120,9 +122,7 @@ export default function AiChatSidebarItem({
className={classes.chatItem}
data-active={isActive || undefined}
>
-
- {chat.title || t("Untitled chat")}
-
+ {chatTitle}
{formattedDate}