💄(frontend) improve ui/ux before release

Following the recommendations of the design team,
we lightly improved some UI/UX elements to be
more consistent and user-friendly before the
next release.

It includes the following changes:
- add a background to the grid
- add a fadein to the header buttons
- reduce the generic size icon
- add a title to the doc item
This commit is contained in:
Anthony LC
2026-07-07 10:57:20 +02:00
parent c2864378ed
commit 6a6154659f
8 changed files with 103 additions and 22 deletions
@@ -142,7 +142,7 @@
"icon": {
"src": "/assets/icon-docs.svg",
"style": {
"width": "40px",
"width": "36px",
"height": "auto"
},
"alt": "",
@@ -1,3 +1,6 @@
import { PropsWithChildren, useEffect, useState } from 'react';
import styled, { keyframes } from 'styled-components';
export const showEffect = `
transform: scaleY(1);
opacity: 1;
@@ -9,3 +12,56 @@ export const hideEffect = `
opacity: 0;
max-height: 0;
`;
const fadeIn = keyframes`
from {
opacity: 0;
}
to {
opacity: 1;
}
`;
const fadeOut = keyframes`
from {
opacity: 1;
}
to {
opacity: 0;
}
`;
const FadeItem = styled.div<{ $isVisible: boolean }>`
display: flex;
animation: ${({ $isVisible }) => ($isVisible ? fadeIn : fadeOut)} 0.2s ease
forwards;
`;
export const FadeComponent = ({
children,
isVisible,
}: PropsWithChildren<{ isVisible: boolean }>) => {
const [isGroupMounted, setIsGroupMounted] = useState(isVisible);
useEffect(() => {
if (isVisible) {
setIsGroupMounted(true);
}
}, [isVisible]);
const handleFadeOutEnd = () => {
if (!isVisible) {
setIsGroupMounted(false);
}
};
if (!isGroupMounted) {
return null;
}
return (
<FadeItem $isVisible={isVisible} onAnimationEnd={handleFadeOutEnd}>
{children}
</FadeItem>
);
};
@@ -100,6 +100,7 @@ export const SimpleDocItem = ({
$weight="500"
$css={ItemTextCss}
data-testid="doc-title"
title={docTitle}
>
{docTitle}
</Text>
@@ -90,10 +90,9 @@ export const DocsGrid = ({
<DocsGridLoader isLoading={isRefetching || loading || isImportPending} />
<Card
data-testid="docs-grid"
$height="100%"
$width="100%"
$css={css`
border: none;
border: 1px solid var(--c--contextuals--border--surface--primary);
${isDragOver
? `
border: 2px dashed var(--c--contextuals--border--semantic--brand--primary);
@@ -1,5 +1,6 @@
import { useTranslation } from 'react-i18next';
import { FadeComponent } from '@/components/Effect';
import { CardFloatingBar, FloatingBar } from '@/components/FloatingBar';
import { DocSearchButtonModal } from '@/features/docs/doc-search/components/DocSearchButtonModal';
import { LeftPanelCollapseButton } from '@/features/left-panel/components/LeftPanelCollapseButton';
@@ -13,19 +14,21 @@ export const HeaderFloatingBar = () => {
const { t } = useTranslation();
const { isPanelOpen } = useLeftPanelStore();
const isVisible = (isTablet && !isPanelOpen) || isMobile;
return (
<FloatingBar $align="center">
{isTablet && (
<LeftPanelCollapseButton ariaLabel={t('Toggle left panel')} />
)}
{(isTablet && !isPanelOpen) || isMobile ? (
<>
<HeaderIcon />
<CardFloatingBar>
<DocSearchButtonModal size="small" color="neutral" />
</CardFloatingBar>
</>
) : null}
<FadeComponent isVisible={isVisible}>
<HeaderIcon />
</FadeComponent>
<FadeComponent isVisible={isVisible}>
<CardFloatingBar>
<DocSearchButtonModal size="small" color="neutral" />
</CardFloatingBar>
</FadeComponent>
</FloatingBar>
);
};
@@ -1,6 +1,7 @@
import { Button } from '@gouvfr-lasuite/cunningham-react';
import { Text } from '@/components';
import { FadeComponent } from '@/components/Effect';
import { CardFloatingBar } from '@/components/FloatingBar';
import LeftPanelIcon from '../assets/left-panel.svg';
@@ -27,15 +28,16 @@ export const LeftPanelCollapseButton = ({
icon={<LeftPanelIcon width={24} height={24} aria-hidden="true" />}
data-testid="floating-bar-toggle-left-panel"
></Button>
{buttonTitle && (
<FadeComponent isVisible={!!buttonTitle}>
<Text
$size="sm"
$weight={700}
$color="var(--c--globals--colors--gray-1000)"
$padding={{ right: '2xs' }}
>
{buttonTitle}
</Text>
)}
</FadeComponent>
</CardFloatingBar>
);
};
@@ -2,7 +2,7 @@ import { PropsWithChildren } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box, BoxProps } from '@/components';
import { Box, BoxType } from '@/components';
import { LeftPanel, ResizableLeftPanel } from '@/features/left-panel';
import { RightPanel } from '@/features/right-panel/components/RightPanel';
import { DocEditorSkeleton, Skeleton } from '@/features/skeletons';
@@ -12,11 +12,15 @@ import { usePanelCoordination } from './usePanelCoordination';
type MainLayoutProps = {
enableResizablePanel?: boolean;
propsLayout?: BoxType;
propsContent?: BoxType;
};
export function MainLayout({
children,
enableResizablePanel = false,
propsLayout,
propsContent,
}: PropsWithChildren<MainLayoutProps>) {
return (
<Box
@@ -24,42 +28,50 @@ export function MainLayout({
$direction="row"
$width="100%"
$height="100dvh"
{...propsLayout}
>
<MainLayoutContent enableResizablePanel={enableResizablePanel}>
<MainLayoutContent
enableResizablePanel={enableResizablePanel}
{...propsContent}
>
{children}
</MainLayoutContent>
</Box>
);
}
export interface MainLayoutContentProps {
export interface MainLayoutContentProps extends BoxType {
enableResizablePanel: boolean;
}
export function MainLayoutContent({
children,
enableResizablePanel,
...props
}: PropsWithChildren<MainLayoutContentProps>) {
if (enableResizablePanel) {
return <MainResizableLayout>{children}</MainResizableLayout>;
return <MainResizableLayout {...props}>{children}</MainResizableLayout>;
}
return (
<>
<LeftPanel />
<MainContent>{children}</MainContent>
<MainContent {...props}>{children}</MainContent>
<RightPanel />
</>
);
}
const MainResizableLayout = ({ children }: PropsWithChildren) => {
const MainResizableLayout = ({
children,
...props
}: PropsWithChildren<BoxType>) => {
usePanelCoordination();
return (
<ResizableLeftPanel>
<Box $direction="row" $width="100%" $position="relative">
<MainContent $flex="auto" $padding="0">
<MainContent $flex="auto" $padding="0" {...props}>
{children}
</MainContent>
<RightPanel />
@@ -71,7 +83,7 @@ const MainResizableLayout = ({ children }: PropsWithChildren) => {
export const MainContent = ({
children,
...props
}: PropsWithChildren<BoxProps>) => {
}: PropsWithChildren<BoxType>) => {
const { t } = useTranslation();
return (
@@ -35,7 +35,15 @@ const Page: NextPageWithLayout = () => {
};
Page.getLayout = function getLayout(page: ReactElement) {
return <MainLayout>{page}</MainLayout>;
return (
<MainLayout
propsContent={{
$background: 'var(--c--contextuals--background--surface--tertiary)',
}}
>
{page}
</MainLayout>
);
};
export default Page;