diff --git a/public/manual/BLOQUE_3_MATERIAL_SANITARIO_Y_OXIGENOTERAPIA/BLOQUE_03_2B_CANULA_OROFARINGEA.md b/public/manual/BLOQUE_3_MATERIAL_SANITARIO_Y_OXIGENOTERAPIA/BLOQUE_03_2B_CANULA_OROFARINGEA.md index 0c3834bf..05fb5179 100644 --- a/public/manual/BLOQUE_3_MATERIAL_SANITARIO_Y_OXIGENOTERAPIA/BLOQUE_03_2B_CANULA_OROFARINGEA.md +++ b/public/manual/BLOQUE_3_MATERIAL_SANITARIO_Y_OXIGENOTERAPIA/BLOQUE_03_2B_CANULA_OROFARINGEA.md @@ -12,6 +12,8 @@ ## 1. OBJETIVO OPERATIVO +![Cánulas de Guedel y nasofaríngea](/assets/infografias/bloque-3-material-sanitario/canulas-guedel-nasofaringea.png) + Insertar cánula orofaríngea (OPA) de forma segura y efectiva en pacientes inconscientes sin reflejo nauseoso, manteniendo vía aérea permeable para facilitar ventilación e integrando con **ventilación con bolsa-mascarilla (3.1) y evaluación primaria ABCDE (1.2)**. Este capítulo se centra en **técnica operativa de inserción de OPA**, no en dispositivos avanzados de vía aérea. diff --git a/public/manual/BLOQUE_3_MATERIAL_SANITARIO_Y_OXIGENOTERAPIA/BLOQUE_03_3_BVM.md b/public/manual/BLOQUE_3_MATERIAL_SANITARIO_Y_OXIGENOTERAPIA/BLOQUE_03_3_BVM.md index 11d72d1f..0bf2a19f 100644 --- a/public/manual/BLOQUE_3_MATERIAL_SANITARIO_Y_OXIGENOTERAPIA/BLOQUE_03_3_BVM.md +++ b/public/manual/BLOQUE_3_MATERIAL_SANITARIO_Y_OXIGENOTERAPIA/BLOQUE_03_3_BVM.md @@ -10,6 +10,10 @@ ## 3.3.1 Objetivo operativo +![Uso correcto de la bolsa-mascarilla (Ambú)](/assets/infografias/bloque-3-material-sanitario/uso-correcto-ambu.png) + +![Configuración máxima de FiO2 con bolsa-mascarilla](/assets/infografias/bloque-3-material-sanitario/configuracion-maxima-fio2-bolsa-mascarilla.png) + Usar la BVM de forma **segura y eficaz** para ventilación asistida básica, integrándola con **oxigenoterapia (3.0–3.1), aspiración (3.2) y traslado**, minimizando **fugas, insuflación gástrica y pérdida de control**. Este capítulo se centra en **material, montaje, técnica de sellado y coordinación**, no en ventilación avanzada, fármacos o decisiones clínicas complejas. diff --git a/src/App.tsx b/src/App.tsx index 41a04855..b4302afe 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, Suspense, lazy } from 'react'; import { Toaster } from "@/components/ui/toaster"; import { Toaster as Sonner } from "@/components/ui/sonner"; import { TooltipProvider } from "@/components/ui/tooltip"; @@ -12,28 +12,35 @@ import SearchModal from "@/components/layout/SearchModal"; import MenuSheet from "@/components/layout/MenuSheet"; import UpdateNotification from "@/components/layout/UpdateNotification"; import InstallBanner from "@/components/layout/InstallBanner"; -import Home from "./pages/Index"; -import SoporteVital from "./pages/SoporteVital"; -import Patologias from "./pages/Patologias"; -import Escena from "./pages/Escena"; -import Farmacos from "./pages/Farmacos"; -import Herramientas from "./pages/Herramientas"; -import Material from "./pages/Material"; -import Telefono from "./pages/Telefono"; -import Comunicacion from "./pages/Comunicacion"; -import ManualIndex from "./pages/ManualIndex"; -import ManualViewer from "./pages/ManualViewer"; -import NotFound from "./pages/NotFound"; -import RCP from "./pages/RCP"; -import Ictus from "./pages/Ictus"; -import Shock from "./pages/Shock"; -import ViaAerea from "./pages/ViaAerea"; -import Favoritos from "./pages/Favoritos"; -import Historial from "./pages/Historial"; -import Ajustes from "./pages/Ajustes"; -import Acerca from "./pages/Acerca"; -import GaleriaImagenes from "./pages/GaleriaImagenes"; import ErrorBoundary from "@/components/ErrorBoundary"; +import PageLoader from "@/components/ui/PageLoader"; + +// Página principal - cargar inmediatamente (crítica) +import Home from "./pages/Index"; +import NotFound from "./pages/NotFound"; + +// Lazy loading de páginas de contenido (cargar bajo demanda) +const SoporteVital = lazy(() => import("./pages/SoporteVital")); +const Patologias = lazy(() => import("./pages/Patologias")); +const Escena = lazy(() => import("./pages/Escena")); +const Farmacos = lazy(() => import("./pages/Farmacos")); +const Herramientas = lazy(() => import("./pages/Herramientas")); +const Material = lazy(() => import("./pages/Material")); +const Telefono = lazy(() => import("./pages/Telefono")); +const Comunicacion = lazy(() => import("./pages/Comunicacion")); +const ManualIndex = lazy(() => import("./pages/ManualIndex")); +const ManualViewer = lazy(() => import("./pages/ManualViewer")); +const RCP = lazy(() => import("./pages/RCP")); +const Ictus = lazy(() => import("./pages/Ictus")); +const Shock = lazy(() => import("./pages/Shock")); +const ViaAerea = lazy(() => import("./pages/ViaAerea")); + +// Lazy loading de páginas de utilidades +const Favoritos = lazy(() => import("./pages/Favoritos")); +const Historial = lazy(() => import("./pages/Historial")); +const Ajustes = lazy(() => import("./pages/Ajustes")); +const Acerca = lazy(() => import("./pages/Acerca")); +const GaleriaImagenes = lazy(() => import("./pages/GaleriaImagenes")); const queryClient = new QueryClient(); @@ -57,32 +64,34 @@ const App = () => {
- - setIsSearchOpen(true)} />} - /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - + }> + + setIsSearchOpen(true)} />} + /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
diff --git a/src/components/ui/PageLoader.tsx b/src/components/ui/PageLoader.tsx new file mode 100644 index 00000000..cbe42125 --- /dev/null +++ b/src/components/ui/PageLoader.tsx @@ -0,0 +1,12 @@ +import { Loader2 } from 'lucide-react'; + +const PageLoader = () => { + return ( +
+ +

Cargando...

+
+ ); +}; + +export default PageLoader; diff --git a/vite.config.ts b/vite.config.ts index eee8a712..26ad989d 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -44,8 +44,83 @@ export default defineConfig({ // Configuración de build para incluir archivos .md e imágenes build: { rollupOptions: { - // Asegurar que los archivos .md e imágenes se copien al build + // Code splitting: dividir el bundle en chunks más pequeños output: { + manualChunks: (id) => { + // Separar node_modules en chunks por librería + if (id.includes('node_modules')) { + // React y React DOM juntos (crítico, cargar primero) + if (id.includes('react') || id.includes('react-dom')) { + return 'vendor-react'; + } + // React Router (crítico para navegación) + if (id.includes('react-router')) { + return 'vendor-router'; + } + // Markdown y procesamiento de texto (grande, separar) + if (id.includes('react-markdown') || id.includes('remark') || id.includes('rehype') || id.includes('unified') || id.includes('micromark') || id.includes('mdast')) { + return 'vendor-markdown'; + } + // Radix UI (componentes UI, agrupar) + if (id.includes('@radix-ui')) { + return 'vendor-ui'; + } + // TanStack Query + if (id.includes('@tanstack')) { + return 'vendor-query'; + } + // Icons (lucide-react) + if (id.includes('lucide-react')) { + return 'vendor-icons'; + } + // Charts (recharts, si se usa) + if (id.includes('recharts')) { + return 'vendor-charts'; + } + // Formularios (react-hook-form, zod) + if (id.includes('react-hook-form') || id.includes('zod') || id.includes('@hookform')) { + return 'vendor-forms'; + } + // Date/time (date-fns, react-day-picker) + if (id.includes('date-fns') || id.includes('react-day-picker')) { + return 'vendor-dates'; + } + // Carousel (embla) + if (id.includes('embla')) { + return 'vendor-carousel'; + } + // Themes (next-themes) + if (id.includes('next-themes')) { + return 'vendor-themes'; + } + // Sonner (toasts) + if (id.includes('sonner')) { + return 'vendor-toasts'; + } + // Resto de node_modules pequeños + return 'vendor-other'; + } + + // Separar páginas en chunks individuales + if (id.includes('/src/pages/')) { + const pageName = id.split('/src/pages/')[1]?.split('.')[0]; + if (pageName) { + // ManualViewer es muy grande, mantenerlo separado + if (pageName === 'ManualViewer') { + return 'page-manual-viewer'; + } + return `page-${pageName.toLowerCase()}`; + } + } + + // Separar componentes grandes + if (id.includes('/src/components/')) { + // MarkdownViewer es grande (usa react-markdown) + if (id.includes('MarkdownViewer')) { + return 'component-markdown'; + } + } + }, assetFileNames: (assetInfo) => { const name = assetInfo.name || '';