diff --git a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/_index.scss b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/_index.scss
index c2de6d08..af2e4a4b 100644
--- a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/_index.scss
+++ b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/_index.scss
@@ -51,9 +51,9 @@
&__section-header {
display: flex;
justify-content: space-between;
- align-items: baseline;
- gap: var(--c--globals--spacings--s);
- margin-bottom: var(--c--globals--spacings--xs);
+ align-items: center;
+ gap: var(--c--globals--spacings--2xs);
+ margin-bottom: var(--c--globals--spacings--base);
}
&__section-title {
diff --git a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/access-tab/index.tsx b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/access-tab/index.tsx
index 1153f8b0..9c6322b8 100644
--- a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/access-tab/index.tsx
+++ b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/access-tab/index.tsx
@@ -1,5 +1,6 @@
import { Button } from "@gouvfr-lasuite/cunningham-react";
-import { Icon, ShareMemberItem, ShareModal } from "@gouvfr-lasuite/ui-kit";
+import { ShareMemberItem, ShareModal, useResponsive } from "@gouvfr-lasuite/ui-kit";
+import { Icon } from "@/features/ui/components/icon";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import {
@@ -14,6 +15,7 @@ import {
useMailboxAccessManagement,
} from "@/hooks/use-mailbox-access-management";
import { ResourceSectionHeader } from "../resource-section-header";
+import { UserAdd } from "@gouvfr-lasuite/ui-kit/icons";
type MailboxSettingsAccessTabProps = {
mailbox: Mailbox;
@@ -26,6 +28,7 @@ export const MailboxSettingsAccessTab = ({
const { user } = useAuth();
const { refetchMailboxes } = useMailboxContext();
const [isAddMemberOpen, setIsAddMemberOpen] = useState(false);
+ const { isMobile } = useResponsive();
// Only mailbox admins reach this tab (the settings modal filters on
// `manage_accesses`), so the accesses list is always fetched. `noGlobalError`
@@ -80,11 +83,12 @@ export const MailboxSettingsAccessTab = ({
})}
action={
}
+ size={isMobile ? "small" : "nano"}
+ icon={
}
onClick={() => setIsAddMemberOpen(true)}
+ aria-label={isMobile ? t("Add a member") : undefined}
>
- {t("Add a member")}
+ {!isMobile && t("Add a member")}
}
/>
diff --git a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/autoreplies-tab/index.tsx b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/autoreplies-tab/index.tsx
index 582305f3..7633cc35 100644
--- a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/autoreplies-tab/index.tsx
+++ b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/autoreplies-tab/index.tsx
@@ -34,7 +34,7 @@ export const MailboxSettingsAutorepliesTab = ({
? t("No auto-reply")
: t("{{count}} auto-reply", { count })
}
- action={
}
+ action={
}
/>
diff --git a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/imports-tab/index.tsx b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/imports-tab/index.tsx
index 8a979ab8..be3c6722 100644
--- a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/imports-tab/index.tsx
+++ b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/imports-tab/index.tsx
@@ -1,5 +1,5 @@
import { Button } from "@gouvfr-lasuite/cunningham-react";
-import { Icon } from "@gouvfr-lasuite/ui-kit";
+import { useResponsive } from "@gouvfr-lasuite/ui-kit";
import { useTranslation } from "react-i18next";
import { useQueryClient } from "@tanstack/react-query";
import {
@@ -7,6 +7,8 @@ import {
getMailboxesImportsListQueryKey,
useMailboxesImportsList,
} from "@/features/api/gen";
+import { Icon } from "@/features/ui/components/icon";
+import { Plus } from "@gouvfr-lasuite/ui-kit/icons";
import { addToast, ToasterItem } from "@/features/ui/components/toaster";
import { ImportsDataGrid } from "../../imports-view/imports-data-grid";
import { ImportNewView } from "../../imports-view/import-new-view";
@@ -30,6 +32,7 @@ export const MailboxSettingsImportsTab = ({
}: MailboxSettingsImportsTabProps) => {
const { t } = useTranslation();
const queryClient = useQueryClient();
+ const { isMobile } = useResponsive();
const { data } = useMailboxesImportsList(mailbox.id, {
query: { enabled: !!mailbox.id },
});
@@ -78,11 +81,12 @@ export const MailboxSettingsImportsTab = ({
}
action={
}
+ size={isMobile ? "small" : "nano"}
+ icon={
}
onClick={() => onViewChange("new")}
+ aria-label={isMobile ? t("New import") : undefined}
>
- {t("New import")}
+ {!isMobile && t("New import")}
}
/>
diff --git a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/index.tsx b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/index.tsx
index 4af8dacd..1aabec75 100644
--- a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/index.tsx
+++ b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/index.tsx
@@ -3,7 +3,7 @@ import {
ModalSize,
ModalTab,
} from "@gouvfr-lasuite/cunningham-react";
-import { HorizontalSeparator } from "@gouvfr-lasuite/ui-kit";
+import { HorizontalSeparator, useResponsive } from "@gouvfr-lasuite/ui-kit";
import { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { useMailboxContext } from "@/features/providers/mailbox";
@@ -14,6 +14,10 @@ import {
useConfirmUnsavedChanges,
} from "@/features/hooks/use-confirm-before-close";
import { useRestoreFocusOnNestedModalClose } from "@/features/hooks/use-restore-focus-on-nested-modal-close";
+import {
+ COMPACT_TAB_MODAL_MEDIA_QUERY,
+ useCompactTabDrillDown,
+} from "@/features/hooks/use-compact-tab-drill-down";
import { MailboxSettingsGeneralTab } from "./general-tab";
import { MailboxSettingsAccessTab } from "./access-tab";
import { MailboxSettingsSignaturesTab } from "./signatures-tab";
@@ -43,12 +47,6 @@ type ModalMailboxSettingsProps = {
export const MODAL_MAILBOX_SETTINGS_ID = "modal-mailbox-settings";
-// Below this width Cunningham's tab modal collapses into a sidebar→content
-// drill-down (its internal `@media (max-width: 576px)`). We read the same
-// breakpoint so the open-time tab selection matches the layout actually shown —
-// the sidebar↔content view itself can't be driven from outside the component.
-const COMPACT_MODAL_MEDIA_QUERY = "(max-width: 576px)";
-
/**
* Settings modal for a mailbox the user can configure. Built on Cunningham's
* "tab" modal layout: the sidebar lists setting categories (General — rename —,
@@ -70,6 +68,7 @@ export const ModalMailboxSettings = ({
initialTab,
initialImportsView,
}: ModalMailboxSettingsProps) => {
+ const { isMobile } = useResponsive();
const { t } = useTranslation();
const { mailboxes, selectedMailbox } = useMailboxContext();
const isIntegrationsEnabled = useFeatureFlag(FEATURE_KEYS.MAILBOX_ADMIN_CHANNELS);
@@ -108,6 +107,10 @@ export const ModalMailboxSettings = ({
// keep a focus anchor and Escape keeps working.
useRestoreFocusOnNestedModalClose(isOpen);
+ // Cunningham's compact layout would otherwise open on the bare sidebar even
+ // with `initialTab` set; this drills straight into the requested tab's content.
+ const drillDownRef = useCompactTabDrillDown(Boolean(initialTab));
+
const settingsMailbox =
settingsMailboxes.find((mailbox) => mailbox.id === selectedMailboxId) ??
(selectedMailbox?.abilities.manage_accesses ||
@@ -132,7 +135,7 @@ export const ModalMailboxSettings = ({
}
if (
typeof window !== "undefined" &&
- window.matchMedia(COMPACT_MODAL_MEDIA_QUERY).matches
+ window.matchMedia(COMPACT_TAB_MODAL_MEDIA_QUERY).matches
) {
return "";
}
@@ -362,9 +365,13 @@ export const ModalMailboxSettings = ({
isOpen={isOpen}
aria-label={t("Settings")}
onClose={guardedOnClose}
- size={ModalSize.LARGE}
+ size={isMobile ? ModalSize.FULL : ModalSize.LARGE}
variant="tab"
- sidebarTitle={
{sidebarHeader}
}
+ sidebarTitle={
+
+ {sidebarHeader}
+
+ }
tabs={tabs}
activeTab={activeTab}
onTabChange={async (tabId) => {
diff --git a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/integrations-tab/index.tsx b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/integrations-tab/index.tsx
index b688cbbf..73e68401 100644
--- a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/integrations-tab/index.tsx
+++ b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/integrations-tab/index.tsx
@@ -28,7 +28,7 @@ export const MailboxSettingsIntegrationsTab = ({
? t("No integration")
: t("{{count}} integration", { count })
}
- action={
}
+ action={
}
/>
diff --git a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/message-templates-tab/index.tsx b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/message-templates-tab/index.tsx
index 140e594c..0c72cc43 100644
--- a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/message-templates-tab/index.tsx
+++ b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/message-templates-tab/index.tsx
@@ -34,7 +34,7 @@ export const MailboxSettingsMessageTemplatesTab = ({
? t("No message template")
: t("{{count}} message template", { count })
}
- action={
}
+ action={
}
/>
diff --git a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/signatures-tab/index.tsx b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/signatures-tab/index.tsx
index f19956f6..977ac0ed 100644
--- a/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/signatures-tab/index.tsx
+++ b/src/frontend/src/features/layouts/components/mailbox-settings/modal-mailbox-settings/signatures-tab/index.tsx
@@ -34,7 +34,7 @@ export const MailboxSettingsSignaturesTab = ({
? t("No signatures")
: t("{{count}} signature", { count })
}
- action={
}
+ action={
}
/>
diff --git a/src/frontend/src/features/layouts/components/mailbox-settings/signatures-view/compose-signature-action.tsx b/src/frontend/src/features/layouts/components/mailbox-settings/signatures-view/compose-signature-action.tsx
index 787663a1..108e28dc 100644
--- a/src/frontend/src/features/layouts/components/mailbox-settings/signatures-view/compose-signature-action.tsx
+++ b/src/frontend/src/features/layouts/components/mailbox-settings/signatures-view/compose-signature-action.tsx
@@ -1,27 +1,30 @@
-import { Button, ButtonProps } from "@gouvfr-lasuite/cunningham-react";
-import { Icon } from "@gouvfr-lasuite/ui-kit";
+import { Button } from "@gouvfr-lasuite/cunningham-react";
+import { useResponsive } from "@gouvfr-lasuite/ui-kit";
import { useTranslation } from "react-i18next";
import { useModal } from "@gouvfr-lasuite/cunningham-react";
import { Mailbox } from "@/features/api/gen";
import { ModalComposeMailboxSignature } from "../modal-compose-mailbox-signature";
+import { Icon } from "@/features/ui/components/icon";
+import { Plus } from "@gouvfr-lasuite/ui-kit/icons";
type ComposeSignatureActionProps = {
mailbox: Mailbox;
- size?: ButtonProps["size"];
};
-export const ComposeSignatureAction = ({ mailbox, size }: ComposeSignatureActionProps) => {
+export const ComposeSignatureAction = ({ mailbox }: ComposeSignatureActionProps) => {
const { t } = useTranslation();
const modal = useModal();
+ const { isMobile } = useResponsive();
return (
<>
{
- const { t } = useTranslation();
- const { isDesktop } = useResponsive();
-
return (
-
- }
- />
-
{leftIcon}
- {isDesktop && (
- <>
-
-
- >
- )}
-
+
+ { !isNativePlatform() && }
);
diff --git a/src/frontend/src/features/layouts/components/main/header/authenticated.tsx b/src/frontend/src/features/layouts/components/main/header/authenticated.tsx
index ed28ce83..e884af09 100644
--- a/src/frontend/src/features/layouts/components/main/header/authenticated.tsx
+++ b/src/frontend/src/features/layouts/components/main/header/authenticated.tsx
@@ -1,6 +1,6 @@
-import { DropdownMenu, HeaderProps, Icon, useResponsive, UserMenu, VerticalSeparator } from "@gouvfr-lasuite/ui-kit";
-import { Controls, GearRounded, Upload } from "@gouvfr-lasuite/ui-kit/icons";
-import { Button, Tooltip, useCunningham } from "@gouvfr-lasuite/cunningham-react";
+import { DropdownMenu, HeaderProps, useResponsive, UserMenu, VerticalSeparator } from "@gouvfr-lasuite/ui-kit";
+import { Controls, GearRounded, LeftPanel, Upload, XMark } from "@gouvfr-lasuite/ui-kit/icons";
+import { Button, Tooltip } from "@gouvfr-lasuite/cunningham-react";
import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "@tanstack/react-router";
@@ -21,6 +21,8 @@ import { useOpenImporter } from "@/features/layouts/components/mailbox-settings/
import { MODAL_NOTIFICATIONS_ID } from "@/features/layouts/components/notifications-settings/modal-notifications";
import { useModalStore } from "@/features/providers/modal-store";
import { useConfig } from "@/features/providers/config";
+import { isNativePlatform } from "@/features/native/platform";
+import { Icon } from "@/features/ui/components/icon";
type AuthenticatedHeaderProps = HeaderProps & {
@@ -33,8 +35,14 @@ export const AuthenticatedHeader = ({
isPanelOpen,
hideSearch = false,
}: AuthenticatedHeaderProps) => {
- const { t } = useCunningham();
+ const { t } = useTranslation();
const { isDesktop } = useResponsive();
+ // The native app has no room for the search field in its single-row header:
+ // it exposes a trigger in the trailing slot that opens the search form
+ // full-screen, and the field itself is never mounted.
+ const isNative = isNativePlatform();
+ const showSearchField = !hideSearch && !isNative;
+ const showSearchTrigger = !hideSearch && isNative;
return (
@@ -45,22 +53,21 @@ export const AuthenticatedHeader = ({
aria-label={isPanelOpen ? t("Close the menu") : t("Open the menu")}
color="brand"
variant="tertiary"
- icon={
-
- }
+ icon={}
/>
{leftIcon}
-
- {!hideSearch && }
-
- {isDesktop && (
-
-
+ {showSearchField && (
+
+
)}
+
+ {showSearchTrigger && }
+ {isDesktop && }
+
);
};
@@ -154,14 +161,14 @@ const ImportIndicator = () => {
);
const progress = withTotal.length
? Math.min(
- 99,
- Math.round(
- withTotal.reduce(
- (sum, r) => sum + (r.progress ?? 0) * (r.total_messages ?? 0),
- 0,
- ) / totalMessages,
- ),
- )
+ 99,
+ Math.round(
+ withTotal.reduce(
+ (sum, r) => sum + (r.progress ?? 0) * (r.total_messages ?? 0),
+ 0,
+ ) / totalMessages,
+ ),
+ )
: null;
return (
@@ -198,7 +205,7 @@ export const HeaderRight = () => {
{isDesktop && }
-
+ {!isNativePlatform() && }