diff --git a/src/App.tsx b/src/App.tsx index bcbda826..93d7cfd5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,7 +9,44 @@ import { PluginsProvider } from './contexts/PluginsContext'; import AppContent from './components/app/AppContent'; import i18n from './i18n/config.js'; +function detectRouterBasename() { + const explicitBasename = typeof window !== 'undefined' ? window.__ROUTER_BASENAME__ || '' : ''; + if (explicitBasename) { + return explicitBasename.replace(/\/+$/, ''); + } + + if (typeof window === 'undefined' || typeof document === 'undefined') { + return ''; + } + + const candidatePaths = [ + document.querySelector('link[rel="manifest"]')?.getAttribute('href'), + document.querySelector('script[type="module"][src]')?.getAttribute('src'), + document.querySelector('link[rel="icon"][href]')?.getAttribute('href'), + ].filter((value): value is string => Boolean(value)); + + let detectedBasename = ''; + for (const candidate of candidatePaths) { + try { + const pathname = new URL(candidate, document.baseURI || window.location.href).pathname; + const match = pathname.match(/^(.*)\/(?:assets\/|manifest\.json$|favicon\.(?:svg|png)$)/); + if (match) { + const normalized = match[1] ? match[1].replace(/\/+$/, '') : ''; + if (normalized.length > detectedBasename.length) { + detectedBasename = normalized; + } + } + } catch { + // Ignore invalid candidate URLs and continue checking other hints. + } + } + + return detectedBasename; +} + export default function App() { + const routerBasename = detectRouterBasename(); + return ( @@ -19,7 +56,7 @@ export default function App() { - + } /> } />