diff --git a/components/contacts/__tests__/contacts-app.test.tsx b/components/contacts/__tests__/contacts-app.test.tsx
index 6e21e3ee7..f373cbb39 100644
--- a/components/contacts/__tests__/contacts-app.test.tsx
+++ b/components/contacts/__tests__/contacts-app.test.tsx
@@ -211,4 +211,17 @@ describe('ContactsApp', () => {
act(() => { contacts!.commands.find((c) => c.id === 'new-contact')!.run(); });
expect(screen.getByPlaceholderText('middle_name')).toBeInTheDocument();
});
+
+ it('puts New group and Import in the phone header menu', () => {
+ const matchMedia = window.matchMedia;
+ window.matchMedia = ((query: string) => ({ ...matchMedia(query), matches: query.includes('max-width') })) as typeof window.matchMedia;
+ try {
+ renderContacts();
+ fireEvent.click(screen.getByRole('button', { name: 'more' }));
+ fireEvent.click(screen.getByText('import.title'));
+ expect(screen.getByRole('dialog', { name: 'import.title' })).toBeInTheDocument();
+ } finally {
+ window.matchMedia = matchMedia;
+ }
+ });
});
diff --git a/components/contacts/contact-list.tsx b/components/contacts/contact-list.tsx
index c597bfa87..fa1bb9263 100644
--- a/components/contacts/contact-list.tsx
+++ b/components/contacts/contact-list.tsx
@@ -123,6 +123,8 @@ interface ContactListProps {
onMoveContacts?: (ids: string[]) => void;
/** Show a burger button at the start that opens the (overlay) categories sidebar. */
onMenuClick?: () => void;
+ /** Contacts' own entries in the phone header's ⋮. */
+ phoneMenuItems?: (close: () => void) => React.ReactNode;
/** The first fetch is still running: show placeholders, not "No contacts yet". */
isLoading?: boolean;
}
@@ -150,6 +152,7 @@ export function ContactList({
onDuplicateContact,
onMoveContacts,
onMenuClick,
+ phoneMenuItems,
isLoading = false,
}: ContactListProps) {
const t = useTranslations("contacts");
@@ -439,7 +442,7 @@ export function ContactList({
)}
-
+
diff --git a/components/contacts/contacts-app.tsx b/components/contacts/contacts-app.tsx
index 25e1de47a..7012590b2 100644
--- a/components/contacts/contacts-app.tsx
+++ b/components/contacts/contacts-app.tsx
@@ -6,6 +6,7 @@ import { useSearchParams } from "next/navigation";
import { useRouter } from "@/i18n/navigation";
import { ArrowLeft, Users, UsersRound, AlertTriangle, Plus, UserPlus, Upload, BookPlus } from "@/components/icons";
import { Button } from "@/components/ui/button";
+import { ContextMenuItem } from "@/components/ui/context-menu";
import { ConfirmDialog } from "@/components/ui/confirm-dialog";
import { useConfirmDialog } from "@/hooks/use-confirm-dialog";
import { ContactList } from "@/components/contacts/contact-list";
@@ -1293,6 +1294,13 @@ function ContactsAppContent({ linkSegments: routeSegments }: ContactsAppProps =
onDuplicateContact={(contact) => void handleDuplicateContact(contact)}
onMoveContacts={canMoveContacts ? handleMoveContacts : undefined}
onMenuClick={isNarrow ? () => setNarrowSidebarOpen(true) : undefined}
+ phoneMenuItems={(close) => (
+ // On the phone these are otherwise only in the drawer's "+".
+ <>
+ { close(); guard(handleCreateGroup)(); }} />
+ { close(); setShowImportDialog(true); }} />
+ >
+ )}
isLoading={supportsSync && !contactsLoaded}
/>
)}
diff --git a/components/files/files-header.tsx b/components/files/files-header.tsx
index 1c865fcdf..23bfc4849 100644
--- a/components/files/files-header.tsx
+++ b/components/files/files-header.tsx
@@ -367,7 +367,13 @@ export function FilesHeader({
)}
-
+ (
+ // The phone header has no room for Refresh as a button.
+ { close(); onRefresh(); }} disabled={isLoading} />
+ )}
+ />
)}