Top Bar petits écrans
This commit is contained in:
@@ -217,10 +217,22 @@ function IconPlusCircle() {
|
||||
);
|
||||
}
|
||||
|
||||
const IconBurger = () => (
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none"
|
||||
stroke="currentColor" strokeWidth="2" strokeLinecap="round"
|
||||
aria-hidden="true">
|
||||
<line x1="4" y1="8" x2="24" y2="8"/>
|
||||
<line x1="4" y1="14" x2="24" y2="14"/>
|
||||
<line x1="4" y1="20" x2="24" y2="20"/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default function Layout() {
|
||||
const { sidebarCollapsed, setSidebarCollapsed, toggleSidebar, displayMode, setDisplayMode } = useUi();
|
||||
const navigate = useNavigate();
|
||||
const [navIcons, setNavIcons] = useState({});
|
||||
const [burgerOpen, setBurgerOpen] = useState(false);
|
||||
const burgerRef = useRef(null);
|
||||
|
||||
// Auto-collapse en mode portrait sur tablette (768–1200px)
|
||||
useEffect(() => {
|
||||
@@ -231,6 +243,16 @@ export default function Layout() {
|
||||
return () => mq.removeEventListener('change', handler);
|
||||
}, [setSidebarCollapsed]);
|
||||
|
||||
// Fermer le burger au clic extérieur
|
||||
useEffect(() => {
|
||||
if (!burgerOpen) return;
|
||||
const handler = (e) => {
|
||||
if (burgerRef.current && !burgerRef.current.contains(e.target)) setBurgerOpen(false);
|
||||
};
|
||||
document.addEventListener('mousedown', handler);
|
||||
return () => document.removeEventListener('mousedown', handler);
|
||||
}, [burgerOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
api.get('/icons').then(rows => {
|
||||
const m = {};
|
||||
@@ -302,28 +324,55 @@ export default function Layout() {
|
||||
<div className="topbar topbar-global">
|
||||
<ProjectSearch />
|
||||
<div className="topbar-right">
|
||||
<button
|
||||
className="btn-add-invest"
|
||||
onClick={() => navigate('/investissements?new=1')}
|
||||
>
|
||||
<IconPlusCircle />
|
||||
Ajout Investissement
|
||||
{/* Boutons visibles sur grand écran */}
|
||||
<button className="btn-add-invest topbar-action-btn" onClick={() => navigate('/investissements?new=1')}>
|
||||
<IconPlusCircle />Ajout Investissement
|
||||
</button>
|
||||
<button
|
||||
className="btn-add-invest"
|
||||
onClick={() => navigate('/remboursements?new=1')}
|
||||
>
|
||||
<IconPlusCircle />
|
||||
Nouveau remboursement
|
||||
<button className="btn-add-invest topbar-action-btn" onClick={() => navigate('/remboursements?new=1')}>
|
||||
<IconPlusCircle />Nouveau remboursement
|
||||
</button>
|
||||
<button
|
||||
className="btn-add-invest"
|
||||
onClick={() => navigate('/depots-retraits?new=1')}
|
||||
>
|
||||
<IconPlusCircle />
|
||||
Nouveau dépôt/retrait
|
||||
<button className="btn-add-invest topbar-action-btn" onClick={() => navigate('/depots-retraits?new=1')}>
|
||||
<IconPlusCircle />Nouveau dépôt/retrait
|
||||
</button>
|
||||
|
||||
{/* Bouton burger — visible sur tablette/mobile */}
|
||||
<div className="topbar-burger-wrap" ref={burgerRef}>
|
||||
<button
|
||||
className="topbar-burger-btn"
|
||||
onClick={() => setBurgerOpen(v => !v)}
|
||||
aria-label="Menu actions"
|
||||
aria-expanded={burgerOpen}
|
||||
>
|
||||
<IconBurger />
|
||||
</button>
|
||||
{burgerOpen && (
|
||||
<div className="topbar-burger-menu">
|
||||
<button className="topbar-burger-search-item" onClick={() => { setBurgerOpen(false); document.querySelector('.project-search-input')?.focus(); }}>
|
||||
<svg width="15" height="15" viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" aria-hidden="true"><circle cx="7.5" cy="7.5" r="5.5"/><line x1="11.5" y1="11.5" x2="16" y2="16"/></svg>
|
||||
Rechercher un projet
|
||||
</button>
|
||||
<div className="topbar-burger-sep" />
|
||||
<button className="topbar-burger-item" onClick={() => { setBurgerOpen(false); navigate('/investissements?new=1'); }}>
|
||||
<IconPlusCircle />Ajout Investissement
|
||||
</button>
|
||||
<button className="topbar-burger-item" onClick={() => { setBurgerOpen(false); navigate('/remboursements?new=1'); }}>
|
||||
<IconPlusCircle />Nouveau remboursement
|
||||
</button>
|
||||
<button className="topbar-burger-item" onClick={() => { setBurgerOpen(false); navigate('/depots-retraits?new=1'); }}>
|
||||
<IconPlusCircle />Nouveau dépôt/retrait
|
||||
</button>
|
||||
<div className="topbar-burger-sep" />
|
||||
<div className="topbar-burger-toggle">
|
||||
<span className="topbar-burger-toggle-label">Affichage</span>
|
||||
<div className="display-toggle" role="group" aria-label="Mode d'affichage">
|
||||
<button className={`display-toggle-btn${displayMode === 'brut' ? ' active' : ''}`} onClick={() => setDisplayMode('brut')} aria-pressed={displayMode === 'brut'}>Brut</button>
|
||||
<button className={`display-toggle-btn${displayMode === 'net' ? ' active' : ''}`} onClick={() => setDisplayMode('net')} aria-pressed={displayMode === 'net'}>Net</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="display-toggle" role="group" aria-label="Mode d'affichage">
|
||||
<button
|
||||
className={`display-toggle-btn${displayMode === 'brut' ? ' active' : ''}`}
|
||||
|
||||
@@ -240,6 +240,69 @@ a { color: var(--primary); }
|
||||
}
|
||||
.btn-add-invest:hover { background: var(--primary-hover); box-shadow: 0 3px 12px rgba(59,130,246,.5); }
|
||||
|
||||
/* ── Burger menu topbar ──────────────────────────────────────── */
|
||||
.topbar-burger-wrap { position: relative; display: none; }
|
||||
.topbar-burger-btn {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 0; background: none; border: none;
|
||||
cursor: pointer; color: var(--text);
|
||||
transition: color .15s;
|
||||
}
|
||||
.topbar-burger-btn:hover { color: var(--primary); }
|
||||
.topbar-burger-menu {
|
||||
position: absolute; top: calc(100% + 8px); right: 0;
|
||||
background: var(--surface); border: 1px solid var(--border);
|
||||
border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,.10);
|
||||
min-width: 220px; z-index: 200; padding: 6px;
|
||||
display: flex; flex-direction: column; gap: 2px;
|
||||
}
|
||||
.topbar-burger-item {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
padding: 9px 12px; border: none; border-radius: 6px;
|
||||
background: none; color: var(--text); font-size: var(--fs-base);
|
||||
font-weight: 600; cursor: pointer; text-align: left; width: 100%;
|
||||
transition: background .12s;
|
||||
}
|
||||
.topbar-burger-item:hover { background: var(--surface-2); }
|
||||
.topbar-burger-item svg { color: var(--primary); flex-shrink: 0; }
|
||||
.topbar-burger-search-item {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
padding: 9px 12px; border: none; border-radius: 6px;
|
||||
background: none; color: var(--text-muted); font-size: var(--fs-sm);
|
||||
cursor: pointer; text-align: left; width: 100%;
|
||||
transition: background .12s;
|
||||
}
|
||||
.topbar-burger-search-item:hover { background: var(--surface-2); }
|
||||
.topbar-burger-sep { height: 1px; background: var(--border); margin: 2px 0; }
|
||||
|
||||
/* Bloc toggle dans le burger */
|
||||
.topbar-burger-toggle {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
padding: 6px 12px 4px;
|
||||
}
|
||||
.topbar-burger-toggle-label {
|
||||
font-size: var(--fs-sm); color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* Tablette : masquer les boutons texte et le toggle, afficher le burger */
|
||||
@media (max-width: 1100px) {
|
||||
.topbar-action-btn { display: none !important; }
|
||||
.topbar-burger-wrap { display: block; }
|
||||
.topbar-global .topbar-right > .display-toggle { display: none; }
|
||||
}
|
||||
|
||||
/* Mobile : masquer aussi la barre de recherche dans la topbar */
|
||||
@media (max-width: 640px) {
|
||||
.topbar-global .project-search-wrap { display: none; }
|
||||
.topbar-burger-search-item { display: flex; }
|
||||
}
|
||||
|
||||
/* Sur tablette, masquer l'item recherche dans le burger (search reste visible) */
|
||||
@media (min-width: 641px) and (max-width: 1100px) {
|
||||
.topbar-burger-search-item,
|
||||
.topbar-burger-search-item + .topbar-burger-sep { display: none; }
|
||||
}
|
||||
|
||||
/* btn-icon — bouton icône discret (cercle hover) */
|
||||
.btn-icon {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
|
||||
Reference in New Issue
Block a user