feat: Enhance application structure with new Prueba_appshell page and responsive navbar; update dependencies

This commit is contained in:
2025-05-06 01:14:08 +02:00
parent 27f71a05f3
commit 00fd103112
9 changed files with 193 additions and 19 deletions
@@ -0,0 +1,41 @@
import { useDisclosure } from '@mantine/hooks';
import { AppShell, Burger, Group, Skeleton } from '@mantine/core';
export function CollapseDesktop() {
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure();
const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(true);
return (
<AppShell
header={{ height: 60 }}
navbar={{
width: 300,
breakpoint: 'sm',
collapsed: { mobile: !mobileOpened, desktop: !desktopOpened },
}}
padding="md"
>
<AppShell.Header>
<Group h="100%" px="md">
<Burger opened={mobileOpened} onClick={toggleMobile} hiddenFrom="sm" size="sm" />
<Burger opened={desktopOpened} onClick={toggleDesktop} visibleFrom="sm" size="sm" />
<img
src="/src/favicon.svg"
alt="Logo"
style={{ width: 30, height: 30 }}
/>
</Group>
</AppShell.Header>
<AppShell.Navbar p="md">
Navbar
{Array(15)
.fill(0)
.map((_, index) => (
<Skeleton key={index} h={28} mt="sm" animate={false} />
))}
</AppShell.Navbar>
<AppShell.Main>Main</AppShell.Main>
</AppShell>
);
}
+29 -14
View File
@@ -15,8 +15,9 @@ import {
UnstyledButton,
ActionIcon,
} from '@mantine/core';
import { useDisclosure, useMediaQuery } from '@mantine/hooks';
import { Link, useLocation } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';
import classes from './DoubleNavbar.module.css';
const mainLinksdata = [
@@ -33,6 +34,7 @@ const submenuLinks: Record<string, { label: string; to: string }[]> = {
Home: [
{ label: 'Inicio', to: '/' },
{ label: 'Consulta Api', to: '/Consulta_API' },
{ label: 'Prueba_appshell', to: '/prueba_appshell' },
],
Dashboard: [
{ label: 'Resumen', to: '/dashboard/resumen' },
@@ -64,10 +66,15 @@ const submenuLinks: Record<string, { label: string; to: string }[]> = {
export function DoubleNavbar() {
const location = useLocation();
const [collapsed, setCollapsed] = useState(false);
const isMobile = useMediaQuery('(max-width: 768px)');
const [mobileOpened, { toggle: toggleMobile, close: closeMobile }] = useDisclosure(false);
const [desktopOpened, { toggle: toggleDesktop, open: openDesktop }] = useDisclosure(true);
const isCollapsed = useMemo(() => (isMobile ? !mobileOpened : !desktopOpened), [isMobile, mobileOpened, desktopOpened]);
const [manualActiveTab, setManualActiveTab] = useState<string | null>(null);
// Detectar cuál pestaña es activa por la ruta actual
const matchedMain = Object.entries(submenuLinks).find(([mainKey, items]) =>
items.some((item) => location.pathname.startsWith(item.to))
);
@@ -87,7 +94,10 @@ export function DoubleNavbar() {
key={link.label}
>
<UnstyledButton
onClick={() => setManualActiveTab(link.label)}
onClick={() => {
setManualActiveTab(link.label);
if (isMobile) closeMobile();
}}
className={classes.mainLink}
data-active={link.label === active || undefined}
>
@@ -102,22 +112,29 @@ export function DoubleNavbar() {
data-active={activeLink === item.label || undefined}
to={item.to}
key={item.label}
style={{ display: collapsed ? 'none' : 'block' }}
style={{ display: isCollapsed ? 'none' : 'block' }}
onClick={() => {
if (isMobile) closeMobile();
}}
>
{item.label}
</Link>
));
// Resetea pestaña seleccionada si la ruta cambia (opcional)
// Restaurar pestaña al cambiar ruta (opcional pero útil)
useEffect(() => {
setManualActiveTab(null);
}, [location.pathname]);
// Abrir navbar de escritorio si cambia a pantalla grande
useEffect(() => {
if (!isMobile) openDesktop();
}, [isMobile, openDesktop]);
return (
<nav className={`${classes.navbar} ${collapsed ? classes.collapsed : ''}`}>
<nav className={`${classes.navbar} ${isCollapsed ? classes.collapsed : ''}`}>
<div className={classes.wrapper}>
<div className={classes.aside}>
{/* Sección superior: logo + mainLinks */}
<div className={classes.topSection}>
<div className={classes.logo}>
<img
@@ -126,23 +143,21 @@ export function DoubleNavbar() {
style={{ width: 30, height: 30 }}
/>
</div>
{mainLinks}
</div>
{/* Botón de colapsar separado abajo */}
<ActionIcon
variant="subtle"
onClick={() => setCollapsed((c) => !c)}
onClick={() => (isMobile ? toggleMobile() : toggleDesktop())}
className={classes.collapseButton}
size="lg"
>
{collapsed ? <IconArrowBarRight size={20} /> : <IconArrowBarLeft size={20} />}
{isCollapsed ? <IconArrowBarRight size={20} /> : <IconArrowBarLeft size={20} />}
</ActionIcon>
</div>
<div className={classes.main}>
{!collapsed && (
{!isCollapsed && (
<Title order={4} className={classes.title}>
{active}
</Title>
@@ -152,4 +167,4 @@ export function DoubleNavbar() {
</div>
</nav>
);
}
}
+1 -1
View File
@@ -58,7 +58,7 @@ extend({ HoloShaderMaterial });
// 🎥 Plano con el shader
function HoloPlane({ color }: { color: [number, number, number] }) {
const mat = useRef<any>();
const mat = useRef<any>(null);
const { size } = useThree();
useFrame(({ clock }) => {