diff --git a/.claude/settings.local.json b/.claude/settings.local.json
index 0d491fe..b9e748c 100644
--- a/.claude/settings.local.json
+++ b/.claude/settings.local.json
@@ -54,7 +54,14 @@
"Bash(npx eslint:*)",
"Bash(git checkout:*)",
"mcp__plugin_playwright_playwright__browser_hover",
- "mcp__plugin_playwright_playwright__browser_run_code"
+ "mcp__plugin_playwright_playwright__browser_run_code",
+ "WebFetch(domain:pagespeed.web.dev)",
+ "WebFetch(domain:www.googleapis.com)",
+ "Bash(find:*)",
+ "Bash(du -sh:*)",
+ "Bash(sudo apt-get install:*)",
+ "Bash(pdftotext:*)",
+ "Bash(pdftoppm:*)"
]
}
}
diff --git a/index.html b/index.html
index 27e2572..275b4fe 100644
--- a/index.html
+++ b/index.html
@@ -4,11 +4,13 @@
+
CVMIS: CHARLWOOD, A.
-
-
+
+
+
diff --git a/lighthouse.pdf b/lighthouse.pdf
new file mode 100644
index 0000000..5c31ea3
Binary files /dev/null and b/lighthouse.pdf differ
diff --git a/src/App.tsx b/src/App.tsx
index 8466316..b4a520b 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -56,10 +56,9 @@ function App() {
})
useEffect(() => {
- initModel()
- }, [])
-
- useEffect(() => {
+ if (phase === 'login' || phase === 'pmr') {
+ initModel()
+ }
if (phase === 'pmr') {
sessionStorage.setItem('portfolio-visited', String(Date.now()))
}
diff --git a/src/components/DashboardLayout.tsx b/src/components/DashboardLayout.tsx
index b281b7f..c346f72 100644
--- a/src/components/DashboardLayout.tsx
+++ b/src/components/DashboardLayout.tsx
@@ -1,17 +1,18 @@
-import { useState, useEffect, useCallback, useRef, useMemo } from 'react'
+import { useState, useEffect, useCallback, useRef, useMemo, lazy, Suspense } from 'react'
import { motion } from 'framer-motion'
import Sidebar from './Sidebar'
import { MobileBottomNav } from './MobileBottomNav'
-import { CommandPalette } from './CommandPalette'
-import { DetailPanel } from './DetailPanel'
import { PatientSummaryTile } from './tiles/PatientSummaryTile'
import { ParentSection } from './ParentSection'
-import CareerConstellation from './constellation/CareerConstellation'
import { TimelineInterventionsSubsection } from './TimelineInterventionsSubsection'
-import { RepeatMedicationsSubsection } from './RepeatMedicationsSubsection'
import { LastConsultationCard } from './LastConsultationCard'
-import { ChatWidget } from './ChatWidget'
import { MobileOverviewHeader } from './MobileOverviewHeader'
+
+const CommandPalette = lazy(() => import('./CommandPalette').then(m => ({ default: m.CommandPalette })))
+const DetailPanel = lazy(() => import('./DetailPanel').then(m => ({ default: m.DetailPanel })))
+const CareerConstellation = lazy(() => import('./constellation/CareerConstellation'))
+const RepeatMedicationsSubsection = lazy(() => import('./RepeatMedicationsSubsection').then(m => ({ default: m.RepeatMedicationsSubsection })))
+const ChatWidget = lazy(() => import('./ChatWidget').then(m => ({ default: m.ChatWidget })))
import { useActiveSection } from '@/hooks/useActiveSection'
import { useIsMobileNav } from '@/hooks/useIsMobileNav'
import { useDetailPanel } from '@/contexts/DetailPanelContext'
@@ -329,22 +330,26 @@ export function DashboardLayout() {
-
+
+
+
-
+
+
+
@@ -352,17 +357,23 @@ export function DashboardLayout() {
{/* Command palette overlay */}
-
+
+
+
{/* Detail panel */}
-
+
+
+
{/* Floating chat widget */}
-
+
+
+
{/* Mobile bottom navigation */}
{
if (extractor || loading) return
loading = true
try {
- extractor = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2') as FeatureExtractionPipeline
+ const { env, pipeline } = await import('@xenova/transformers')
+ env.localModelPath = '/models/'
+ env.allowRemoteModels = false
+ env.useBrowserCache = false
+ extractor = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2') as import('@xenova/transformers').FeatureExtractionPipeline
} catch {
// Silently swallow — model unavailable, semantic search won't activate
} finally {
diff --git a/vite.config.ts b/vite.config.ts
index 4f387b4..d499de7 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -9,6 +9,20 @@ export default defineConfig({
'@': path.resolve(__dirname, './src'),
},
},
+ build: {
+ rollupOptions: {
+ output: {
+ manualChunks: {
+ 'vendor-react': ['react', 'react-dom'],
+ 'vendor-d3': ['d3'],
+ 'vendor-motion': ['framer-motion'],
+ 'vendor-search': ['fuse.js'],
+ 'vendor-markdown': ['react-markdown'],
+ 'vendor-carousel': ['embla-carousel-react', 'embla-carousel-autoplay'],
+ },
+ },
+ },
+ },
server: {
proxy: {
'/api': 'http://localhost:3000',