fix: version 2.4.0 -- menu lateral como drawer en celular
En pantallas angostas (<=768px) el sidebar arranca oculto y se abre como panel superpuesto desde el boton de hamburguesa, con fondo oscuro detras y cierre automatico al navegar o tocar afuera. El escritorio no se toca: sigue igual que siempre. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
# Changelog - project.linkedcorp.net
|
||||
|
||||
## [2.4.0] - 2026-09-22
|
||||
### Fixed
|
||||
- Menú lateral en celular: antes quedaba siempre visible fijo, ocupando gran parte de una
|
||||
pantalla angosta. Ahora arranca oculto, se abre como un panel superpuesto (con fondo oscuro
|
||||
detrás) desde el botón de hamburguesa, y se cierra solo al elegir una opción o tocar afuera.
|
||||
El escritorio no cambia — sigue con el sidebar fijo y el modo compacto de siempre.
|
||||
|
||||
## [2.3.0] - 2026-09-22
|
||||
### Added
|
||||
- Al iniciar sesión, si sos superadmin y hay una actualización pendiente, aparece un aviso con
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "project-linkedcorp-backend",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/server.js",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "project-linkedcorp-frontend",
|
||||
"private": true,
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -16,8 +16,11 @@ import { getUpdateStatus } from '../services/updater.js';
|
||||
|
||||
const EMPTY_PASSWORD_FORM = { currentPassword: '', newPassword: '', confirmPassword: '' };
|
||||
|
||||
const MOBILE_BREAKPOINT = 768;
|
||||
|
||||
export default function AppShell() {
|
||||
const [navMode, setNavMode] = useState('expanded');
|
||||
const [mobileNavOpen, setMobileNavOpen] = useState(false);
|
||||
const { user, logout } = useAuth();
|
||||
const { t, theme, setTheme, lang, setLang, pushToast, openDialog } = useUi();
|
||||
const navigate = useNavigate();
|
||||
@@ -54,9 +57,20 @@ export default function AppShell() {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// En celular el boton de hamburguesa abre/cierra el drawer superpuesto (mobileNavOpen); en
|
||||
// escritorio, sigue alternando el riel expandido/compacto de siempre -- son dos estados
|
||||
// independientes para no tocar el comportamiento de escritorio ya existente.
|
||||
function toggleNav() {
|
||||
if (window.innerWidth <= MOBILE_BREAKPOINT) {
|
||||
setMobileNavOpen((v) => !v);
|
||||
} else {
|
||||
setNavMode((m) => (m === 'expanded' ? 'compact' : 'expanded'));
|
||||
}
|
||||
}
|
||||
|
||||
function closeMobileNav() {
|
||||
setMobileNavOpen(false);
|
||||
}
|
||||
|
||||
async function handleNotificationClick(notification) {
|
||||
if (!notification.is_read) await markNotificationRead(notification.id);
|
||||
@@ -92,7 +106,8 @@ export default function AppShell() {
|
||||
|
||||
return (
|
||||
<div className="app-shell">
|
||||
<NavigationView mode={navMode} />
|
||||
<NavigationView mode={navMode} mobileOpen={mobileNavOpen} onNavigate={closeMobileNav} />
|
||||
<div className={`nav-backdrop ${mobileNavOpen ? 'visible' : ''}`} onClick={closeMobileNav} />
|
||||
<div className="content-column">
|
||||
<div className="topbar">
|
||||
<div className="topbar-left">
|
||||
|
||||
@@ -17,15 +17,17 @@ const ITEMS = [
|
||||
{ to: '/configuracion', icon: Settings, labelKey: 'nav_config', superadminOnly: true },
|
||||
];
|
||||
|
||||
export function NavigationView({ mode }) {
|
||||
export function NavigationView({ mode, mobileOpen, onNavigate }) {
|
||||
const { t, theme } = useUi();
|
||||
const { user } = useAuth();
|
||||
const branding = useBranding();
|
||||
const compact = mode === 'compact';
|
||||
// En celular el drawer siempre se ve completo (con etiquetas), sin importar el modo
|
||||
// compacto/expandido del riel de escritorio -- son dos cosas independientes.
|
||||
const compact = mode === 'compact' && !mobileOpen;
|
||||
const items = ITEMS.filter((item) => !item.superadminOnly || user?.roleCode === 'superadmin');
|
||||
const brandName = branding.name || t('appName');
|
||||
return (
|
||||
<nav className={`nav-view ${mode}`}>
|
||||
<nav className={`nav-view ${mode} ${mobileOpen ? 'mobile-open' : ''}`}>
|
||||
{branding.logoUrl && (
|
||||
<div className="nav-header">
|
||||
<img
|
||||
@@ -37,9 +39,9 @@ export function NavigationView({ mode }) {
|
||||
)}
|
||||
<div className="nav-items">
|
||||
{items.map((item) => (
|
||||
<NavLink key={item.to} to={item.to} end={item.end} className={({ isActive }) => `nav-item ${isActive ? 'active' : ''}`}>
|
||||
<NavLink key={item.to} to={item.to} end={item.end} onClick={onNavigate} className={({ isActive }) => `nav-item ${isActive ? 'active' : ''}`}>
|
||||
<item.icon />
|
||||
{mode !== 'compact' && <span>{t(item.labelKey)}</span>}
|
||||
{!compact && <span>{t(item.labelKey)}</span>}
|
||||
</NavLink>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -73,6 +73,33 @@ button { font-family: inherit; }
|
||||
.nav-logo-icon-header { width: 72px; height: 72px; flex: none; object-fit: contain; }
|
||||
.nav-logo-full-header { height: 64px; width: auto; max-width: 100%; object-fit: contain; }
|
||||
|
||||
/* --- Menu lateral en celular: todo lo de acá abajo es exclusivo de pantallas angostas, no
|
||||
toca nada del layout de escritorio (que sigue con el sidebar fijo de siempre). --- */
|
||||
.nav-backdrop { display: none; }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.nav-view, .nav-view.compact, .nav-view.expanded {
|
||||
position: fixed;
|
||||
top: 0; left: 0; bottom: 0;
|
||||
width: 260px;
|
||||
z-index: 60;
|
||||
transform: translateX(-100%);
|
||||
transition: transform .2s ease;
|
||||
box-shadow: 4px 0 20px rgb(0 0 0 / .4);
|
||||
}
|
||||
.nav-view.mobile-open { transform: translateX(0); }
|
||||
|
||||
.nav-backdrop {
|
||||
display: block;
|
||||
position: fixed; inset: 0;
|
||||
background: rgb(0 0 0 / .5);
|
||||
z-index: 55;
|
||||
opacity: 0; pointer-events: none;
|
||||
transition: opacity .2s ease;
|
||||
}
|
||||
.nav-backdrop.visible { opacity: 1; pointer-events: auto; }
|
||||
}
|
||||
|
||||
.content-column { flex: 1; display: flex; flex-direction: column; min-width: 0; }
|
||||
.topbar {
|
||||
height: 84px; flex: none; display: flex; align-items: center; justify-content: space-between;
|
||||
|
||||
Reference in New Issue
Block a user