1+ import { useEffect , useState } from 'react' ;
12import { useTranslation } from 'react-i18next' ;
23import Card from '../design-system/Card' ;
34import Typography from '../design-system/Typography' ;
@@ -7,6 +8,7 @@ import TransportModeSelector from './TransportModeSelector';
78import FilterPanel , { Filters } from './FilterPanel' ;
89import LanguageSwitcher from './LanguageSwitcher' ;
910import { Etablissement } from '../types/etablissement' ;
11+ import Button from '../design-system/Button' ;
1012
1113interface HeaderCardProps {
1214 total : number ;
@@ -40,17 +42,53 @@ const HeaderCard: React.FC<HeaderCardProps> = ({
4042 onFiltersReset,
4143} ) => {
4244 const { t } = useTranslation ( ) ;
45+ const getIsMobile = ( ) => ( typeof window !== 'undefined' ? window . matchMedia ( '(max-width: 768px)' ) . matches : false ) ;
46+ const [ isMobile , setIsMobile ] = useState < boolean > ( getIsMobile ) ;
47+ const [ configOpen , setConfigOpen ] = useState < boolean > ( ( ) => ! getIsMobile ( ) ) ;
48+
49+ useEffect ( ( ) => {
50+ const mq = window . matchMedia ( '(max-width: 768px)' ) ;
51+ const update = ( ) => setIsMobile ( mq . matches ) ;
52+ update ( ) ;
53+ mq . addEventListener ( 'change' , update ) ;
54+ return ( ) => mq . removeEventListener ( 'change' , update ) ;
55+ } , [ ] ) ;
56+
57+ useEffect ( ( ) => {
58+ if ( ! isMobile ) setConfigOpen ( true ) ;
59+ } , [ isMobile ] ) ;
4360
4461 return (
4562 < Card >
4663 < div style = { { display : 'flex' , flexDirection : 'row' , gap : 32 , alignItems : 'stretch' , flexWrap : 'wrap' } } >
47- < div style = { { flex : 1 , minWidth : 220 , display : 'flex' , flexDirection : 'column' , justifyContent : 'center' } } >
64+ < div style = { { flex : 1 , minWidth : 220 , display : 'flex' , flexDirection : 'column' , justifyContent : 'center' , gap : 8 } } >
4865 < Typography variant = "h1" > { t ( 'header.title' ) } </ Typography >
4966 < Typography variant = "body" > { t ( 'header.description' ) } </ Typography >
5067 < LanguageSwitcher />
68+ { isMobile && (
69+ < div style = { { marginTop : 8 } } >
70+ < Button
71+ variant = "secondary"
72+ compact
73+ aria-expanded = { configOpen }
74+ onClick = { ( ) => setConfigOpen ( ( v ) => ! v ) }
75+ >
76+ { configOpen ? t ( 'header.hideConfig' ) : t ( 'header.showConfig' ) }
77+ </ Button >
78+ </ div >
79+ ) }
5180 </ div >
52- < div style = { { flex : 2 , minWidth : 220 , display : 'flex' , flexDirection : 'column' , justifyContent : 'center' , gap : 16 } } >
53- < div style = { { marginBottom : 8 , display : 'flex' , flexDirection : 'row' , alignItems : 'center' } } >
81+ < div
82+ style = { {
83+ flex : 2 ,
84+ minWidth : 220 ,
85+ display : 'flex' ,
86+ flexDirection : 'column' ,
87+ justifyContent : 'center' ,
88+ gap : 16 ,
89+ } }
90+ >
91+ < div style = { { marginBottom : 8 , display : isMobile && ! configOpen ? 'none' : 'flex' , flexDirection : 'row' , alignItems : 'center' , flexWrap : 'wrap' } } >
5492 { total > 0 && (
5593 < ProgressBar percent = { percent } resolved = { resolved } total = { total } />
5694 ) }
@@ -60,7 +98,7 @@ const HeaderCard: React.FC<HeaderCardProps> = ({
6098 </ span >
6199 ) }
62100 </ div >
63- < div style = { { display : 'flex' , flexDirection : 'row' , gap : 8 , alignItems : 'center' , flexWrap : 'wrap' } } >
101+ < div style = { { display : isMobile && ! configOpen ? 'none' : 'flex' , flexDirection : 'row' , gap : 8 , alignItems : 'center' , flexWrap : 'wrap' } } >
64102 < TimeSelector value = { timeInMinutes } onChange = { onTimeChange } />
65103 < TransportModeSelector value = { transportMode } onChange = { ( v ) => onTransportModeChange ( v as typeof transportMode ) } />
66104 < FilterPanel
0 commit comments