Compare commits
3 Commits
27f71a05f3
...
234639a34a
| Author | SHA1 | Date | |
|---|---|---|---|
| 234639a34a | |||
| 9ab92c521a | |||
| 00fd103112 |
Generated
+59
@@ -28,6 +28,7 @@
|
|||||||
"@types/node": "^22.13.11",
|
"@types/node": "^22.13.11",
|
||||||
"@types/react": "^19.0.12",
|
"@types/react": "^19.0.12",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
|
"@types/three": "^0.176.0",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"eslint": "^9.23.0",
|
"eslint": "^9.23.0",
|
||||||
"eslint-config-mantine": "^4.0.3",
|
"eslint-config-mantine": "^4.0.3",
|
||||||
@@ -533,6 +534,13 @@
|
|||||||
"@csstools/css-tokenizer": "^3.0.3"
|
"@csstools/css-tokenizer": "^3.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@dimforge/rapier3d-compat": {
|
||||||
|
"version": "0.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz",
|
||||||
|
"integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/@dual-bundle/import-meta-resolve": {
|
"node_modules/@dual-bundle/import-meta-resolve": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
|
||||||
@@ -2215,6 +2223,13 @@
|
|||||||
"@testing-library/dom": ">=7.21.4"
|
"@testing-library/dom": ">=7.21.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tweenjs/tween.js": {
|
||||||
|
"version": "23.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz",
|
||||||
|
"integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/aria-query": {
|
"node_modules/@types/aria-query": {
|
||||||
"version": "5.0.4",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||||
@@ -2333,6 +2348,29 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/stats.js": {
|
||||||
|
"version": "0.17.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz",
|
||||||
|
"integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/three": {
|
||||||
|
"version": "0.176.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.176.0.tgz",
|
||||||
|
"integrity": "sha512-FwfPXxCqOtP7EdYMagCFePNKoG1AGBDUEVKtluv2BTVRpSt7b+X27xNsirPCTCqY1pGYsPUzaM3jgWP7dXSxlw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@dimforge/rapier3d-compat": "^0.12.0",
|
||||||
|
"@tweenjs/tween.js": "~23.1.3",
|
||||||
|
"@types/stats.js": "*",
|
||||||
|
"@types/webxr": "*",
|
||||||
|
"@webgpu/types": "*",
|
||||||
|
"fflate": "~0.8.2",
|
||||||
|
"meshoptimizer": "~0.18.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/webxr": {
|
"node_modules/@types/webxr": {
|
||||||
"version": "0.5.22",
|
"version": "0.5.22",
|
||||||
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz",
|
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz",
|
||||||
@@ -2688,6 +2726,13 @@
|
|||||||
"url": "https://opencollective.com/vitest"
|
"url": "https://opencollective.com/vitest"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@webgpu/types": {
|
||||||
|
"version": "0.1.60",
|
||||||
|
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.60.tgz",
|
||||||
|
"integrity": "sha512-8B/tdfRFKdrnejqmvq95ogp8tf52oZ51p3f4QD5m5Paey/qlX4Rhhy5Y8tgFMi7Ms70HzcMMw3EQjH/jdhTwlA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/accepts": {
|
"node_modules/accepts": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
||||||
@@ -4635,6 +4680,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fflate": {
|
||||||
|
"version": "0.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
||||||
|
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/file-entry-cache": {
|
"node_modules/file-entry-cache": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
|
||||||
@@ -6307,6 +6359,13 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/meshoptimizer": {
|
||||||
|
"version": "0.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz",
|
||||||
|
"integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/micromatch": {
|
"node_modules/micromatch": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
"@types/node": "^22.13.11",
|
"@types/node": "^22.13.11",
|
||||||
"@types/react": "^19.0.12",
|
"@types/react": "^19.0.12",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
|
"@types/three": "^0.176.0",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"eslint": "^9.23.0",
|
"eslint": "^9.23.0",
|
||||||
"eslint-config-mantine": "^4.0.3",
|
"eslint-config-mantine": "^4.0.3",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
|||||||
import { HomePage } from './pages/Home.page';
|
import { HomePage } from './pages/Home.page';
|
||||||
import { Consulta_API } from './pages/Consulta_api';
|
import { Consulta_API } from './pages/Consulta_api';
|
||||||
import { Error_404 } from './pages/404'; // Ajusta si está en otra carpeta
|
import { Error_404 } from './pages/404'; // Ajusta si está en otra carpeta
|
||||||
|
import { Prueba_appshell } from './pages/Prueba_appshell'; // Ajusta si está en otra carpeta
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
@@ -12,6 +13,10 @@ const router = createBrowserRouter([
|
|||||||
path: '/Consulta_API',
|
path: '/Consulta_API',
|
||||||
element: <Consulta_API />,
|
element: <Consulta_API />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/prueba_appshell',
|
||||||
|
element: <Prueba_appshell />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '*',
|
path: '*',
|
||||||
element: <Error_404 />,
|
element: <Error_404 />,
|
||||||
|
|||||||
+17
-29
@@ -10,22 +10,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-family:
|
||||||
.collapsed {
|
Greycliff CF,
|
||||||
width: 70px; /* Ancho reducido cuando colapsa */
|
var(--mantine-font-family);
|
||||||
|
margin-bottom: var(--mantine-spacing-sm);
|
||||||
|
background-color: var(--mantine-color-body);
|
||||||
|
padding: var(--mantine-spacing-md);
|
||||||
|
padding-top: 18px;
|
||||||
|
height: px;
|
||||||
|
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.collapseButton {
|
|
||||||
margin-top: auto; /* Hace que el botón se empuje hacia abajo */
|
|
||||||
margin-bottom: 16px; /* ← Agrega separación del borde inferior */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.aside {
|
.aside {
|
||||||
flex: 0 0 60px;
|
flex: 0 0 60px;
|
||||||
@@ -41,7 +44,12 @@
|
|||||||
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6));
|
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.topSection {
|
||||||
|
padding-top: 12px; /* o la cantidad que desees */
|
||||||
|
}
|
||||||
|
|
||||||
.mainLink {
|
.mainLink {
|
||||||
|
|
||||||
width: 44px;
|
width: 44px;
|
||||||
height: 44px;
|
height: 44px;
|
||||||
border-radius: var(--mantine-radius-md);
|
border-radius: var(--mantine-radius-md);
|
||||||
@@ -63,27 +71,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
|
||||||
font-family:
|
|
||||||
Greycliff CF,
|
|
||||||
var(--mantine-font-family);
|
|
||||||
margin-bottom: var(--mantine-spacing-xl);
|
|
||||||
background-color: var(--mantine-color-body);
|
|
||||||
padding: var(--mantine-spacing-md);
|
|
||||||
padding-top: 18px;
|
|
||||||
height: 60px;
|
|
||||||
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-7));
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
height: 60px;
|
|
||||||
padding-top: var(--mantine-spacing-md);
|
|
||||||
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-7));
|
|
||||||
margin-bottom: var(--mantine-spacing-xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
import {
|
||||||
|
IconCalendarStats,
|
||||||
|
IconDeviceDesktopAnalytics,
|
||||||
|
IconFingerprint,
|
||||||
|
IconGauge,
|
||||||
|
IconHome2,
|
||||||
|
IconSettings,
|
||||||
|
IconUser,
|
||||||
|
IconArrowBarLeft,
|
||||||
|
IconArrowBarRight,
|
||||||
|
} from '@tabler/icons-react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
AppShell,
|
||||||
|
Burger,
|
||||||
|
Group,
|
||||||
|
Skeleton,
|
||||||
|
Tooltip,
|
||||||
|
UnstyledButton,
|
||||||
|
ActionIcon,
|
||||||
|
Title,
|
||||||
|
} from '@mantine/core';
|
||||||
|
|
||||||
|
import { useDisclosure, useMediaQuery } from '@mantine/hooks';
|
||||||
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
import { Link, useLocation } from 'react-router-dom';
|
||||||
|
import classes from './Appshell.module.css';
|
||||||
|
|
||||||
|
const mainLinksdata = [
|
||||||
|
{ icon: IconHome2, label: 'Home' },
|
||||||
|
{ icon: IconGauge, label: 'Dashboard' },
|
||||||
|
{ icon: IconDeviceDesktopAnalytics, label: 'Analytics' },
|
||||||
|
{ icon: IconCalendarStats, label: 'Releases' },
|
||||||
|
{ icon: IconUser, label: 'Account' },
|
||||||
|
{ icon: IconFingerprint, label: 'Security' },
|
||||||
|
{ icon: IconSettings, label: 'Settings' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const submenuLinks = {
|
||||||
|
Home: [
|
||||||
|
{ label: 'Inicio', to: '/' },
|
||||||
|
{ label: 'Consulta Api', to: '/Consulta_API' },
|
||||||
|
{ label: 'Prueba_appshell', to: '/prueba_appshell' },
|
||||||
|
],
|
||||||
|
Dashboard: [
|
||||||
|
{ label: 'Resumen', to: '/dashboard/resumen' },
|
||||||
|
{ label: 'Estadísticas', to: '/dashboard/estadisticas' },
|
||||||
|
{ label: 'Usuarios', to: '/dashboard/usuarios' },
|
||||||
|
],
|
||||||
|
Analytics: [
|
||||||
|
{ label: 'Conversiones', to: '/analytics/conversiones' },
|
||||||
|
{ label: 'Tráfico', to: '/analytics/trafico' },
|
||||||
|
{ label: 'Tendencias', to: '/analytics/tendencias' },
|
||||||
|
],
|
||||||
|
Releases: [
|
||||||
|
{ label: 'Notas de versión', to: '/releases/notas-de-version' },
|
||||||
|
{ label: 'Historial', to: '/releases/historial' },
|
||||||
|
],
|
||||||
|
Account: [
|
||||||
|
{ label: 'Perfil', to: '/account/perfil' },
|
||||||
|
{ label: 'Suscripciones', to: '/account/suscripciones' },
|
||||||
|
],
|
||||||
|
Security: [
|
||||||
|
{ label: 'Contraseña', to: '/security/contraseña' },
|
||||||
|
{ label: '2FA', to: '/security/2fa' },
|
||||||
|
],
|
||||||
|
Settings: [
|
||||||
|
{ label: 'Preferencias', to: '/settings/preferencias' },
|
||||||
|
{ label: 'Notificaciones', to: '/settings/notificaciones' },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
type AppShellWithMenuProps = {
|
||||||
|
children?: React.ReactNode; // <- ahora es opcional
|
||||||
|
};
|
||||||
|
|
||||||
|
export function AppShellWithMenu({ children }: AppShellWithMenuProps) {
|
||||||
|
|
||||||
|
const location = useLocation();
|
||||||
|
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);
|
||||||
|
|
||||||
|
const matchedMain = Object.entries(submenuLinks).find(([mainKey, items]) =>
|
||||||
|
items.some((item) => location.pathname.startsWith(item.to))
|
||||||
|
);
|
||||||
|
|
||||||
|
const routeBasedActive = matchedMain?.[0] ?? 'Home';
|
||||||
|
const active = manualActiveTab ?? routeBasedActive;
|
||||||
|
const activeLink = submenuLinks[active as keyof typeof submenuLinks]?.find((item) => location.pathname === item.to)?.label ?? '';
|
||||||
|
|
||||||
|
const mainLinks = mainLinksdata.map((link) => (
|
||||||
|
<Tooltip
|
||||||
|
label={link.label}
|
||||||
|
position="right"
|
||||||
|
withArrow
|
||||||
|
transitionProps={{ duration: 0 }}
|
||||||
|
key={link.label}
|
||||||
|
>
|
||||||
|
<UnstyledButton
|
||||||
|
onClick={() => {
|
||||||
|
setManualActiveTab(link.label);
|
||||||
|
if (isMobile) closeMobile();
|
||||||
|
}}
|
||||||
|
className={classes.mainLink}
|
||||||
|
data-active={link.label === active || undefined}
|
||||||
|
>
|
||||||
|
<link.icon size={22} stroke={1.5} />
|
||||||
|
</UnstyledButton>
|
||||||
|
</Tooltip>
|
||||||
|
));
|
||||||
|
|
||||||
|
const links = (submenuLinks[active as keyof typeof submenuLinks] || []).map((item) => (
|
||||||
|
<Link
|
||||||
|
className={classes.link}
|
||||||
|
data-active={activeLink === item.label || undefined}
|
||||||
|
to={item.to}
|
||||||
|
key={item.label}
|
||||||
|
style={{ display: isCollapsed ? 'none' : 'block' }}
|
||||||
|
onClick={() => {
|
||||||
|
if (isMobile) closeMobile();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</Link>
|
||||||
|
));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setManualActiveTab(null);
|
||||||
|
}, [location.pathname]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isMobile) openDesktop();
|
||||||
|
}, [isMobile, openDesktop]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppShell
|
||||||
|
header={{ height: 60 }}
|
||||||
|
navbar={{
|
||||||
|
width: isCollapsed ? 60 : 300,
|
||||||
|
breakpoint: 'sm',
|
||||||
|
collapsed: { mobile: !mobileOpened, desktop: !desktopOpened },
|
||||||
|
}}
|
||||||
|
padding="md"
|
||||||
|
>
|
||||||
|
|
||||||
|
{/* Header */}
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
|
||||||
|
{/* Navbar */}
|
||||||
|
|
||||||
|
<AppShell.Navbar>
|
||||||
|
<div className={classes.wrapper}>
|
||||||
|
<div className={classes.aside}>
|
||||||
|
<div className={classes.topSection}>
|
||||||
|
|
||||||
|
{mainLinks}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className={classes.main}>
|
||||||
|
{!isCollapsed && <Title order={4} className={classes.title}>{active}</Title>}
|
||||||
|
{links}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AppShell.Navbar>
|
||||||
|
|
||||||
|
{/* Main Content */}
|
||||||
|
|
||||||
|
<AppShell.Main>
|
||||||
|
{children}
|
||||||
|
</AppShell.Main>
|
||||||
|
|
||||||
|
|
||||||
|
</AppShell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
import {
|
|
||||||
IconCalendarStats,
|
|
||||||
IconDeviceDesktopAnalytics,
|
|
||||||
IconFingerprint,
|
|
||||||
IconGauge,
|
|
||||||
IconHome2,
|
|
||||||
IconSettings,
|
|
||||||
IconUser,
|
|
||||||
IconArrowBarLeft,
|
|
||||||
IconArrowBarRight,
|
|
||||||
} from '@tabler/icons-react';
|
|
||||||
import {
|
|
||||||
Title,
|
|
||||||
Tooltip,
|
|
||||||
UnstyledButton,
|
|
||||||
ActionIcon,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { Link, useLocation } from 'react-router-dom';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import classes from './DoubleNavbar.module.css';
|
|
||||||
|
|
||||||
const mainLinksdata = [
|
|
||||||
{ icon: IconHome2, label: 'Home' },
|
|
||||||
{ icon: IconGauge, label: 'Dashboard' },
|
|
||||||
{ icon: IconDeviceDesktopAnalytics, label: 'Analytics' },
|
|
||||||
{ icon: IconCalendarStats, label: 'Releases' },
|
|
||||||
{ icon: IconUser, label: 'Account' },
|
|
||||||
{ icon: IconFingerprint, label: 'Security' },
|
|
||||||
{ icon: IconSettings, label: 'Settings' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const submenuLinks: Record<string, { label: string; to: string }[]> = {
|
|
||||||
Home: [
|
|
||||||
{ label: 'Inicio', to: '/' },
|
|
||||||
{ label: 'Consulta Api', to: '/Consulta_API' },
|
|
||||||
],
|
|
||||||
Dashboard: [
|
|
||||||
{ label: 'Resumen', to: '/dashboard/resumen' },
|
|
||||||
{ label: 'Estadísticas', to: '/dashboard/estadisticas' },
|
|
||||||
{ label: 'Usuarios', to: '/dashboard/usuarios' },
|
|
||||||
],
|
|
||||||
Analytics: [
|
|
||||||
{ label: 'Conversiones', to: '/analytics/conversiones' },
|
|
||||||
{ label: 'Tráfico', to: '/analytics/trafico' },
|
|
||||||
{ label: 'Tendencias', to: '/analytics/tendencias' },
|
|
||||||
],
|
|
||||||
Releases: [
|
|
||||||
{ label: 'Notas de versión', to: '/releases/notas-de-version' },
|
|
||||||
{ label: 'Historial', to: '/releases/historial' },
|
|
||||||
],
|
|
||||||
Account: [
|
|
||||||
{ label: 'Perfil', to: '/account/perfil' },
|
|
||||||
{ label: 'Suscripciones', to: '/account/suscripciones' },
|
|
||||||
],
|
|
||||||
Security: [
|
|
||||||
{ label: 'Contraseña', to: '/security/contraseña' },
|
|
||||||
{ label: '2FA', to: '/security/2fa' },
|
|
||||||
],
|
|
||||||
Settings: [
|
|
||||||
{ label: 'Preferencias', to: '/settings/preferencias' },
|
|
||||||
{ label: 'Notificaciones', to: '/settings/notificaciones' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export function DoubleNavbar() {
|
|
||||||
const location = useLocation();
|
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
|
||||||
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))
|
|
||||||
);
|
|
||||||
|
|
||||||
const routeBasedActive = matchedMain?.[0] ?? 'Home';
|
|
||||||
const active = manualActiveTab ?? routeBasedActive;
|
|
||||||
|
|
||||||
const activeLink =
|
|
||||||
submenuLinks[active]?.find((item) => location.pathname === item.to)?.label ?? '';
|
|
||||||
|
|
||||||
const mainLinks = mainLinksdata.map((link) => (
|
|
||||||
<Tooltip
|
|
||||||
label={link.label}
|
|
||||||
position="right"
|
|
||||||
withArrow
|
|
||||||
transitionProps={{ duration: 0 }}
|
|
||||||
key={link.label}
|
|
||||||
>
|
|
||||||
<UnstyledButton
|
|
||||||
onClick={() => setManualActiveTab(link.label)}
|
|
||||||
className={classes.mainLink}
|
|
||||||
data-active={link.label === active || undefined}
|
|
||||||
>
|
|
||||||
<link.icon size={22} stroke={1.5} />
|
|
||||||
</UnstyledButton>
|
|
||||||
</Tooltip>
|
|
||||||
));
|
|
||||||
|
|
||||||
const links = (submenuLinks[active] || []).map((item) => (
|
|
||||||
<Link
|
|
||||||
className={classes.link}
|
|
||||||
data-active={activeLink === item.label || undefined}
|
|
||||||
to={item.to}
|
|
||||||
key={item.label}
|
|
||||||
style={{ display: collapsed ? 'none' : 'block' }}
|
|
||||||
>
|
|
||||||
{item.label}
|
|
||||||
</Link>
|
|
||||||
));
|
|
||||||
|
|
||||||
// Resetea pestaña seleccionada si la ruta cambia (opcional)
|
|
||||||
useEffect(() => {
|
|
||||||
setManualActiveTab(null);
|
|
||||||
}, [location.pathname]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<nav className={`${classes.navbar} ${collapsed ? classes.collapsed : ''}`}>
|
|
||||||
<div className={classes.wrapper}>
|
|
||||||
<div className={classes.aside}>
|
|
||||||
{/* Sección superior: logo + mainLinks */}
|
|
||||||
<div className={classes.topSection}>
|
|
||||||
<div className={classes.logo}>
|
|
||||||
<img
|
|
||||||
src="/src/favicon.svg"
|
|
||||||
alt="Logo"
|
|
||||||
style={{ width: 30, height: 30 }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{mainLinks}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Botón de colapsar separado abajo */}
|
|
||||||
<ActionIcon
|
|
||||||
variant="subtle"
|
|
||||||
onClick={() => setCollapsed((c) => !c)}
|
|
||||||
className={classes.collapseButton}
|
|
||||||
size="lg"
|
|
||||||
>
|
|
||||||
{collapsed ? <IconArrowBarRight size={20} /> : <IconArrowBarLeft size={20} />}
|
|
||||||
</ActionIcon>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classes.main}>
|
|
||||||
{!collapsed && (
|
|
||||||
<Title order={4} className={classes.title}>
|
|
||||||
{active}
|
|
||||||
</Title>
|
|
||||||
)}
|
|
||||||
{links}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -58,7 +58,7 @@ extend({ HoloShaderMaterial });
|
|||||||
|
|
||||||
// 🎥 Plano con el shader
|
// 🎥 Plano con el shader
|
||||||
function HoloPlane({ color }: { color: [number, number, number] }) {
|
function HoloPlane({ color }: { color: [number, number, number] }) {
|
||||||
const mat = useRef<any>();
|
const mat = useRef<any>(null);
|
||||||
const { size } = useThree();
|
const { size } = useThree();
|
||||||
|
|
||||||
useFrame(({ clock }) => {
|
useFrame(({ clock }) => {
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import {
|
||||||
|
TextInput,
|
||||||
|
Textarea,
|
||||||
|
Button,
|
||||||
|
Box,
|
||||||
|
Center,
|
||||||
|
Stack,
|
||||||
|
Badge,
|
||||||
|
Group,
|
||||||
|
} from '@mantine/core';
|
||||||
|
import { MetodoSelect } from './MetodoSelect';
|
||||||
|
|
||||||
|
export function LlamadorAPI() {
|
||||||
|
const [direccion, setDireccion] = useState('http://localhost:8000/api/saludo');
|
||||||
|
const [metodo, setMetodo] = useState('GET');
|
||||||
|
const [contenido, setContenido] = useState('');
|
||||||
|
const [respuesta, setRespuesta] = useState('');
|
||||||
|
const [codigoRespuesta, setCodigoRespuesta] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const colorCodigo = (status: number): string => {
|
||||||
|
if (status >= 200 && status < 300) return 'green';
|
||||||
|
if (status >= 300 && status < 400) return 'yellow';
|
||||||
|
if (status >= 400 && status < 500) return 'orange';
|
||||||
|
return 'red';
|
||||||
|
};
|
||||||
|
|
||||||
|
const llamarAPI = async () => {
|
||||||
|
try {
|
||||||
|
const options: RequestInit = {
|
||||||
|
method: metodo,
|
||||||
|
mode: 'cors',
|
||||||
|
headers: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (metodo !== 'GET') {
|
||||||
|
options.headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
JSON.parse(contenido);
|
||||||
|
options.body = contenido;
|
||||||
|
} catch (err) {
|
||||||
|
setRespuesta('Error: El contenido no es un JSON válido');
|
||||||
|
setCodigoRespuesta(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(direccion, options);
|
||||||
|
setCodigoRespuesta(res.status);
|
||||||
|
|
||||||
|
const contentType = res.headers.get('content-type');
|
||||||
|
|
||||||
|
if (contentType?.includes('application/json')) {
|
||||||
|
const data = await res.json();
|
||||||
|
const formatted = JSON.stringify(data, null, 2);
|
||||||
|
setRespuesta(formatted);
|
||||||
|
} else {
|
||||||
|
const text = await res.text();
|
||||||
|
setRespuesta(text);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Error en la API:', error);
|
||||||
|
setRespuesta(`Error: ${error.message || error}`);
|
||||||
|
setCodigoRespuesta(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = (e: KeyboardEvent) => {
|
||||||
|
if (e.ctrlKey && e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
llamarAPI();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('keydown', handler);
|
||||||
|
return () => window.removeEventListener('keydown', handler);
|
||||||
|
}, [metodo, direccion, contenido]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box style={{ flex: 1, padding: 40 }}>
|
||||||
|
<Center style={{ height: '100%' }}>
|
||||||
|
<Stack style={{ width: 600 }}>
|
||||||
|
<TextInput
|
||||||
|
label="Dirección"
|
||||||
|
placeholder="http://localhost:8000/api/..."
|
||||||
|
value={direccion}
|
||||||
|
onChange={(e) => setDireccion(e.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MetodoSelect metodo={metodo} setMetodo={setMetodo} />
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
label="Contenido (JSON)"
|
||||||
|
placeholder='{"contenido": "Hola"}'
|
||||||
|
value={contenido}
|
||||||
|
onChange={(e) => setContenido(e.currentTarget.value)}
|
||||||
|
autosize
|
||||||
|
minRows={3}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button onClick={llamarAPI} color="blue">
|
||||||
|
Enviar solicitud
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{codigoRespuesta !== null && (
|
||||||
|
<Group>
|
||||||
|
<Badge color={colorCodigo(codigoRespuesta)} size="lg">
|
||||||
|
Código: {codigoRespuesta}
|
||||||
|
</Badge>
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
label="Respuesta de la API"
|
||||||
|
value={respuesta}
|
||||||
|
readOnly
|
||||||
|
autosize
|
||||||
|
minRows={6}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
+12
-10
@@ -1,25 +1,25 @@
|
|||||||
import { Box, Title, Text, Button, Group, Stack, Image, Center } from '@mantine/core';
|
import { Box, Title, Text, Button, Group, Stack, Image, Center } from '@mantine/core';
|
||||||
import { IconArrowLeft } from '@tabler/icons-react';
|
import { IconArrowLeft } from '@tabler/icons-react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { DoubleNavbar } from '../components/DoubleNavbar'; // Ajusta ruta si es necesario
|
|
||||||
import { MantineCardWithShader } from '../components/HoloShader'; // Ajusta ruta si es necesario
|
import { MantineCardWithShader } from '../components/HoloShader'; // Ajusta ruta si es necesario
|
||||||
|
import { AppShellWithMenu } from '../components/Appshell';
|
||||||
|
|
||||||
|
|
||||||
export function Error_404() {
|
export function Error_404() {
|
||||||
return (
|
return (
|
||||||
<Box style={{ display: 'flex', height: '100vh' }}>
|
<AppShellWithMenu>
|
||||||
<DoubleNavbar />
|
<Box style={{
|
||||||
|
flex: 1,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'flex-start', // alinea arriba
|
||||||
|
padding: '2rem',
|
||||||
|
paddingTop: '0.5rem', // agrega espacio desde arriba si deseas
|
||||||
|
}}>
|
||||||
<Box style={{ flex: 1, display: 'flex', justifyContent: 'center', alignItems: 'center', padding: '2rem' }}>
|
<Box style={{ flex: 1, display: 'flex', justifyContent: 'center', alignItems: 'center', padding: '2rem' }}>
|
||||||
|
|
||||||
<Stack align="center" maw={500} mx="auto">
|
<Stack align="center" maw={500} mx="auto">
|
||||||
|
|
||||||
|
|
||||||
<MantineCardWithShader />
|
<MantineCardWithShader />
|
||||||
|
|
||||||
|
|
||||||
<Title order={1}>
|
<Title order={1}>
|
||||||
Página no encontrada
|
Página no encontrada
|
||||||
</Title>
|
</Title>
|
||||||
@@ -43,5 +43,7 @@ export function Error_404() {
|
|||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
</AppShellWithMenu>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2,19 +2,14 @@ import { ColorSchemeToggle } from '../components/ColorSchemeToggle/ColorSchemeTo
|
|||||||
import { Welcome } from '../components/Welcome/Welcome';
|
import { Welcome } from '../components/Welcome/Welcome';
|
||||||
import MiBoton from '../components/botoncito';
|
import MiBoton from '../components/botoncito';
|
||||||
import { Center, Box } from '@mantine/core';
|
import { Center, Box } from '@mantine/core';
|
||||||
import { DoubleNavbar } from '../components/DoubleNavbar';
|
import { AppShellWithMenu } from '../components/Appshell';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function Prueba_1() {
|
export function Prueba_1() {
|
||||||
return (
|
return (
|
||||||
<Box style={{ display: 'flex', height: '100vh' }}>
|
<AppShellWithMenu>
|
||||||
<DoubleNavbar /> {/* Sidebar fijo a la izquierda */}
|
|
||||||
|
|
||||||
{/* Contenido principal */}
|
</AppShellWithMenu>
|
||||||
|
|
||||||
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,139 +1,12 @@
|
|||||||
import { useState } from 'react';
|
import { Box } from '@mantine/core';
|
||||||
import {
|
import { LlamadorAPI } from '../components/LlamadorAPI';
|
||||||
TextInput,
|
import { AppShellWithMenu } from '../components/Appshell';
|
||||||
Textarea,
|
|
||||||
Button,
|
|
||||||
Box,
|
|
||||||
Center,
|
|
||||||
Stack,
|
|
||||||
Badge,
|
|
||||||
Group,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { DoubleNavbar } from '../components/DoubleNavbar';
|
|
||||||
import { MetodoSelect } from '../components/MetodoSelect'; // 👈 Importación del nuevo componente
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function Consulta_API() {
|
export function Consulta_API() {
|
||||||
const [direccion, setDireccion] = useState('http://localhost:8000/api/saludo');
|
|
||||||
const [metodo, setMetodo] = useState('GET');
|
|
||||||
const [contenido, setContenido] = useState('');
|
|
||||||
const [respuesta, setRespuesta] = useState('');
|
|
||||||
const [codigoRespuesta, setCodigoRespuesta] = useState<number | null>(null);
|
|
||||||
|
|
||||||
const colorCodigo = (status: number): string => {
|
|
||||||
if (status >= 200 && status < 300) return 'green';
|
|
||||||
if (status >= 300 && status < 400) return 'yellow';
|
|
||||||
if (status >= 400 && status < 500) return 'orange';
|
|
||||||
return 'red';
|
|
||||||
};
|
|
||||||
|
|
||||||
const llamarAPI = async () => {
|
|
||||||
try {
|
|
||||||
const options: RequestInit = {
|
|
||||||
method: metodo,
|
|
||||||
mode: 'cors',
|
|
||||||
headers: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (metodo !== 'GET') {
|
|
||||||
options.headers = {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
JSON.parse(contenido);
|
|
||||||
options.body = contenido;
|
|
||||||
} catch (err) {
|
|
||||||
setRespuesta('Error: El contenido no es un JSON válido');
|
|
||||||
setCodigoRespuesta(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await fetch(direccion, options);
|
|
||||||
setCodigoRespuesta(res.status);
|
|
||||||
|
|
||||||
const contentType = res.headers.get('content-type');
|
|
||||||
|
|
||||||
if (contentType?.includes('application/json')) {
|
|
||||||
const data = await res.json();
|
|
||||||
const formatted = JSON.stringify(data, null, 2);
|
|
||||||
setRespuesta(formatted);
|
|
||||||
} else {
|
|
||||||
const text = await res.text();
|
|
||||||
setRespuesta(text);
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error('Error en la API:', error);
|
|
||||||
setRespuesta(`Error: ${error.message || error}`);
|
|
||||||
setCodigoRespuesta(null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handler = (e: KeyboardEvent) => {
|
|
||||||
if (e.ctrlKey && e.key === 'Enter') {
|
|
||||||
e.preventDefault();
|
|
||||||
llamarAPI();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('keydown', handler);
|
|
||||||
return () => window.removeEventListener('keydown', handler);
|
|
||||||
}, [metodo, direccion, contenido]);
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box style={{ display: 'flex', height: '100vh' }}>
|
<AppShellWithMenu>
|
||||||
<DoubleNavbar />
|
<LlamadorAPI />
|
||||||
|
</AppShellWithMenu>
|
||||||
<Box style={{ flex: 1, padding: 40 }}>
|
|
||||||
<Center style={{ height: '100%' }}>
|
|
||||||
<Stack style={{ width: 600 }}>
|
|
||||||
<TextInput
|
|
||||||
label="Dirección"
|
|
||||||
placeholder="http://localhost:8000/api/..."
|
|
||||||
value={direccion}
|
|
||||||
onChange={(e) => setDireccion(e.currentTarget.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<MetodoSelect metodo={metodo} setMetodo={setMetodo} />
|
|
||||||
|
|
||||||
<Textarea
|
|
||||||
label="Contenido (JSON)"
|
|
||||||
placeholder='{"contenido": "Hola"}'
|
|
||||||
value={contenido}
|
|
||||||
onChange={(e) => setContenido(e.currentTarget.value)}
|
|
||||||
autosize
|
|
||||||
minRows={3}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button onClick={llamarAPI} color="blue">
|
|
||||||
Enviar solicitud
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{codigoRespuesta !== null && (
|
|
||||||
<Group>
|
|
||||||
<Badge color={colorCodigo(codigoRespuesta)} size="lg">
|
|
||||||
Código: {codigoRespuesta}
|
|
||||||
</Badge>
|
|
||||||
</Group>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Textarea
|
|
||||||
label="Respuesta de la API"
|
|
||||||
value={respuesta}
|
|
||||||
readOnly
|
|
||||||
autosize
|
|
||||||
minRows={6}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
</Center>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,28 +1,10 @@
|
|||||||
import { ColorSchemeToggle } from '../components/ColorSchemeToggle/ColorSchemeToggle';
|
import { AppShellWithMenu } from '../components/Appshell';
|
||||||
import { Welcome } from '../components/Welcome/Welcome';
|
|
||||||
import MiBoton from '../components/botoncito';
|
|
||||||
import { Center, Box } from '@mantine/core';
|
|
||||||
import { DoubleNavbar } from '../components/DoubleNavbar';
|
|
||||||
import { MantineCardWithShader } from '../components/HoloShader';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function HomePage() {
|
export function HomePage() {
|
||||||
return (
|
return (
|
||||||
<Box style={{ display: 'flex', height: '100vh' }}>
|
<AppShellWithMenu>
|
||||||
<DoubleNavbar /> {/* Sidebar fijo a la izquierda */}
|
|
||||||
|
|
||||||
{/* Contenido principal */}
|
</AppShellWithMenu>
|
||||||
<Box style={{ flex: 1, padding: '24px' }}>
|
|
||||||
<Welcome />
|
|
||||||
<ColorSchemeToggle />
|
|
||||||
|
|
||||||
|
|
||||||
<Center mt="md">
|
|
||||||
<MiBoton />
|
|
||||||
</Center>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { AppShellWithMenu } from '../components/Appshell';
|
||||||
|
|
||||||
|
|
||||||
|
export function Plantilla() {
|
||||||
|
return (
|
||||||
|
<AppShellWithMenu>
|
||||||
|
|
||||||
|
</AppShellWithMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { ColorSchemeToggle } from '../components/ColorSchemeToggle/ColorSchemeToggle';
|
||||||
|
import { Welcome } from '../components/Welcome/Welcome';
|
||||||
|
import MiBoton from '../components/botoncito';
|
||||||
|
import { Center, Box } from '@mantine/core';
|
||||||
|
import { MantineCardWithShader } from '../components/HoloShader';
|
||||||
|
import { AppShellWithMenu } from '../components/Appshell';
|
||||||
|
|
||||||
|
export function Prueba_appshell() {
|
||||||
|
return (
|
||||||
|
<AppShellWithMenu>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</AppShellWithMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -222,6 +222,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz"
|
resolved "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz"
|
||||||
integrity sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==
|
integrity sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==
|
||||||
|
|
||||||
|
"@dimforge/rapier3d-compat@^0.12.0":
|
||||||
|
version "0.12.0"
|
||||||
|
resolved "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz"
|
||||||
|
integrity sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==
|
||||||
|
|
||||||
"@dual-bundle/import-meta-resolve@^4.1.0":
|
"@dual-bundle/import-meta-resolve@^4.1.0":
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz"
|
resolved "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz"
|
||||||
@@ -675,6 +680,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz"
|
resolved "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz"
|
||||||
integrity sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==
|
integrity sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==
|
||||||
|
|
||||||
|
"@tweenjs/tween.js@~23.1.3":
|
||||||
|
version "23.1.3"
|
||||||
|
resolved "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz"
|
||||||
|
integrity sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==
|
||||||
|
|
||||||
"@types/aria-query@^5.0.1":
|
"@types/aria-query@^5.0.1":
|
||||||
version "5.0.4"
|
version "5.0.4"
|
||||||
resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz"
|
resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz"
|
||||||
@@ -757,6 +767,24 @@
|
|||||||
resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz"
|
resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz"
|
||||||
integrity sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==
|
integrity sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==
|
||||||
|
|
||||||
|
"@types/stats.js@*":
|
||||||
|
version "0.17.4"
|
||||||
|
resolved "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz"
|
||||||
|
integrity sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==
|
||||||
|
|
||||||
|
"@types/three@^0.176.0":
|
||||||
|
version "0.176.0"
|
||||||
|
resolved "https://registry.npmjs.org/@types/three/-/three-0.176.0.tgz"
|
||||||
|
integrity sha512-FwfPXxCqOtP7EdYMagCFePNKoG1AGBDUEVKtluv2BTVRpSt7b+X27xNsirPCTCqY1pGYsPUzaM3jgWP7dXSxlw==
|
||||||
|
dependencies:
|
||||||
|
"@dimforge/rapier3d-compat" "^0.12.0"
|
||||||
|
"@tweenjs/tween.js" "~23.1.3"
|
||||||
|
"@types/stats.js" "*"
|
||||||
|
"@types/webxr" "*"
|
||||||
|
"@webgpu/types" "*"
|
||||||
|
fflate "~0.8.2"
|
||||||
|
meshoptimizer "~0.18.1"
|
||||||
|
|
||||||
"@types/webxr@*":
|
"@types/webxr@*":
|
||||||
version "0.5.22"
|
version "0.5.22"
|
||||||
resolved "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz"
|
resolved "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz"
|
||||||
@@ -913,6 +941,11 @@
|
|||||||
loupe "^3.1.3"
|
loupe "^3.1.3"
|
||||||
tinyrainbow "^2.0.0"
|
tinyrainbow "^2.0.0"
|
||||||
|
|
||||||
|
"@webgpu/types@*":
|
||||||
|
version "0.1.60"
|
||||||
|
resolved "https://registry.npmjs.org/@webgpu/types/-/types-0.1.60.tgz"
|
||||||
|
integrity sha512-8B/tdfRFKdrnejqmvq95ogp8tf52oZ51p3f4QD5m5Paey/qlX4Rhhy5Y8tgFMi7Ms70HzcMMw3EQjH/jdhTwlA==
|
||||||
|
|
||||||
accepts@^2.0.0:
|
accepts@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz"
|
||||||
@@ -2056,6 +2089,11 @@ fdir@^6.4.4:
|
|||||||
resolved "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz"
|
resolved "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz"
|
||||||
integrity sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==
|
integrity sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==
|
||||||
|
|
||||||
|
fflate@~0.8.2:
|
||||||
|
version "0.8.2"
|
||||||
|
resolved "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz"
|
||||||
|
integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
|
||||||
|
|
||||||
file-entry-cache@^10.0.8:
|
file-entry-cache@^10.0.8:
|
||||||
version "10.0.8"
|
version "10.0.8"
|
||||||
resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.0.8.tgz"
|
resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.0.8.tgz"
|
||||||
@@ -2983,6 +3021,11 @@ merge2@^1.3.0, merge2@^1.4.1:
|
|||||||
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
|
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
|
||||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||||
|
|
||||||
|
meshoptimizer@~0.18.1:
|
||||||
|
version "0.18.1"
|
||||||
|
resolved "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz"
|
||||||
|
integrity sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==
|
||||||
|
|
||||||
micromatch@^4.0.8:
|
micromatch@^4.0.8:
|
||||||
version "4.0.8"
|
version "4.0.8"
|
||||||
resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz"
|
resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz"
|
||||||
|
|||||||
Reference in New Issue
Block a user