♻️(frontend) reuse the left panel footer on public layouts

The home and simple layouts rendered their own mobile-only panel with
just the gaufre. Reusing the explorer footer keeps the settings entry
and user profile consistent everywhere and removes the duplicate
component. The index page is also reformatted by prettier on the way.
This commit is contained in:
Nathan Vasse
2026-07-23 17:08:12 +02:00
parent d42dd3061a
commit 635135d1ed
7 changed files with 40 additions and 66 deletions
@@ -1,8 +1,17 @@
@use "sass:map";
@use "@/styles/cunningham-tokens-sass" as *;
$tablet: map.get($themes, "default", "globals", "breakpoints", "tablet");
.c__left-panel__footer__drive {
padding: 12px;
display: flex;
gap: 4px;
align-items: center;
@media (max-width: $tablet) {
justify-content: space-between;
}
}
// Toast component from cunningham-react is not used in the drive app, so we hide it.
@@ -29,3 +38,9 @@
.c__tooltip__content {
word-break: break-word;
}
.user-profile {
display: flex;
align-items: center;
gap: 4px;
}
@@ -1,18 +0,0 @@
.drive__home__left-panel {
display: flex;
justify-content: center;
align-items: center;
padding: 0.75rem 0;
gap: 12px;
}
.drive__home__left-panel__gaufre {
position: absolute;
bottom: 0;
padding: 8px 10px;
border-top: 1px solid var(--c--contextuals--border--surface--primary);
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
}
@@ -1,18 +0,0 @@
import { Gaufre } from "@/features/ui/components/gaufre/Gaufre";
import { useResponsive } from "@gouvfr-lasuite/ui-kit";
export const LeftPanelMobile = () => {
const { isTablet } = useResponsive();
if (!isTablet) {
return null;
}
return (
<div className="drive__home__left-panel">
<div className="drive__home__left-panel__gaufre">
<Gaufre />
</div>
</div>
);
};
@@ -2,7 +2,7 @@ import { MainLayout } from "@gouvfr-lasuite/ui-kit";
import { GlobalLayout } from "../global/GlobalLayout";
import { HeaderRight } from "../header/Header";
import { Toaster } from "@/features/ui/components/toaster/Toaster";
import { LeftPanelMobile } from "@/features/layouts/components/left-panel/LeftPanelMobile";
import { LeftPanelFooter } from "../explorer/ExplorerLayout";
export const getSimpleLayout = (page: React.ReactElement) => {
return <SimpleLayout>{page}</SimpleLayout>;
@@ -20,7 +20,7 @@ export const SimpleLayout = ({ children }: { children: React.ReactNode }) => {
<MainLayout
enableResize
hideLeftPanelOnDesktop={true}
leftPanelContent={<LeftPanelMobile />}
leftPanelFooter={<LeftPanelFooter />}
rightHeaderContent={<HeaderRight />}
>
{children}
@@ -19,7 +19,7 @@ import { useClipboard } from "@/hooks/useCopyToClipboard";
export const UserProfile = () => {
const { user } = useAuth();
return (
<>
<div className="user-profile">
{user ? (
<UserMenu
user={user}
@@ -33,7 +33,7 @@ export const UserProfile = () => {
<AnonymousCTA />
</>
)}
</>
</div>
);
};
+21 -25
View File
@@ -14,11 +14,10 @@ import {
} from "@/features/ui/components/toaster/Toaster";
import { Button } from "@gouvfr-lasuite/cunningham-react";
import { useConfig } from "@/features/config/ConfigProvider";
import { LeftPanelMobile } from "@/features/layouts/components/left-panel/LeftPanelMobile";
import { useThemeCustomization } from "@/hooks/useThemeCustomization";
import { Feedback } from "@/features/feedback/Feedback";
import { useRedirectAfterLogin } from "@/hooks/useRedirectAfterLogin";
import { LeftPanelFooter } from "@/features/layouts/components/explorer/ExplorerLayout";
export default function HomePage() {
const { t } = useTranslation();
@@ -28,14 +27,14 @@ export default function HomePage() {
useEffect(() => {
const failure = new URLSearchParams(window.location.search).get(
"auth_error"
"auth_error",
);
if (failure === "alpha") {
addToast(
<ToasterItem type="error">
<span className="material-icons">science</span>
<span>{t("authentication.error.alpha")}</span>
</ToasterItem>
</ToasterItem>,
);
}
if (failure === "user_cannot_access_app") {
@@ -43,7 +42,7 @@ export default function HomePage() {
<ToasterItem type="error">
<span className="material-icons">lock</span>
<span>{t("authentication.error.user_cannot_access_app")}</span>
</ToasterItem>
</ToasterItem>,
);
}
}, []);
@@ -58,10 +57,10 @@ export default function HomePage() {
/**
* If the FRONTEND_EXTERNAL_HOME_URL is set, we redirect to it.
* Otherwise, we display the home page.
*
*
* Redirection to FRONTEND_EXTERNAL_HOME_URL is done in this component
* to avoid conflicts with the useEffect and redirection logic in the HomePage component.
*
*
* HomePage: if there is a user, redirect to the explorer.
* HomePageContent: if the FRONTEND_EXTERNAL_HOME_URL is set, we redirect to it.
* Otherwise, we display the home page.
@@ -70,7 +69,7 @@ const HomePageContent = () => {
const { t } = useTranslation();
const { config } = useConfig();
const footerCustommization = useThemeCustomization("footer");
const [redirectFailed, setRedirectFailed] = useState(false)
const [redirectFailed, setRedirectFailed] = useState(false);
useEffect(() => {
const checkSiteAndRedirect = async () => {
@@ -80,18 +79,18 @@ const HomePageContent = () => {
try {
// Make sure the site is reachable before redirecting. Resilience.
await fetch(config.FRONTEND_EXTERNAL_HOME_URL, {
method: 'HEAD', // Use HEAD to avoid downloading the full page
mode: 'no-cors', // Needed for cross-origin requests
})
window.location.replace(config.FRONTEND_EXTERNAL_HOME_URL)
method: "HEAD", // Use HEAD to avoid downloading the full page
mode: "no-cors", // Needed for cross-origin requests
});
window.location.replace(config.FRONTEND_EXTERNAL_HOME_URL);
} catch (error) {
console.warn('Site is not reachable:', error)
setRedirectFailed(true)
console.warn("Site is not reachable:", error);
setRedirectFailed(true);
}
}
};
checkSiteAndRedirect()
}, [config?.FRONTEND_EXTERNAL_HOME_URL])
checkSiteAndRedirect();
}, [config?.FRONTEND_EXTERNAL_HOME_URL]);
if (config?.FRONTEND_EXTERNAL_HOME_URL && !redirectFailed) {
return null;
@@ -137,15 +136,14 @@ const HomePageContent = () => {
<Footer {...footerCustommization} />
</HomePageLayout>
);
}
};
const HomePageLayout = ({children}: {children: React.ReactNode}) => {
const HomePageLayout = ({ children }: { children: React.ReactNode }) => {
return (
<MainLayout
enableResize
hideLeftPanelOnDesktop={true}
leftPanelContent={<LeftPanelMobile />}
leftPanelFooter={<LeftPanelFooter />}
icon={
<div className="drive__header__left">
<img src={logoGouv.src} alt="" />
@@ -159,7 +157,7 @@ const HomePageLayout = ({children}: {children: React.ReactNode}) => {
<Toaster />
</MainLayout>
);
}
};
/**
* Only context stuff, containing Auth, etc ...
@@ -170,9 +168,7 @@ const HomePageLayout = ({children}: {children: React.ReactNode}) => {
HomePage.getLayout = function getLayout(page: React.ReactElement) {
return (
<div className="drive__home drive__home--feedback">
<GlobalLayout>
{page}
</GlobalLayout>
<GlobalLayout>{page}</GlobalLayout>
</div>
);
};
@@ -25,7 +25,6 @@
@use "./../features/ui/components/spinner/SpinnerPage.scss";
@use "./../features/ui/components/loading-ring/LoadingRing.scss";
@use "./../features/ui/components/infinite-scroll/InfiniteScroll.scss";
@use "./../features/layouts/components/left-panel/LeftPanelMobile.scss";
@use "./../pages/index.scss" as *;
@use "./../pages/sdk/index.scss" as *;
body {