Spaces:
Running
Running
File size: 3,144 Bytes
c993983 7c893d7 c993983 43662e2 7c893d7 43662e2 c993983 7c893d7 c993983 7c893d7 c993983 9d4a3ad c993983 34b735d 43662e2 c993983 7c893d7 c993983 7c893d7 c993983 7c893d7 c993983 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | import { type ReactNode, useEffect } from 'react';
import { NavLink } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { useUIStore } from '../../store/uiStore';
import './AppShell.css';
interface Props {
children: ReactNode;
}
const NAV_ITEMS = [
{ path: '/', translationKey: 'appshell.nav.home', icon: <img src="/favicon.svg" alt="HTP" style={{ width: '1.2em', height: '1.2em', display: 'block' }} /> },
{ path: '/data-collection', translationKey: 'appshell.nav.data_collection', icon: 'π' },
{ path: '/potential-analysis', translationKey: 'appshell.nav.potential_analysis', icon: 'π' },
];
export default function AppShell({ children }: Props) {
const { t, i18n } = useTranslation();
const theme = useUIStore((s) => s.theme);
const toggleTheme = useUIStore((s) => s.toggleTheme);
const toggleLanguage = () => {
const nextLang = i18n.language === 'en' ? 'de' : 'en';
i18n.changeLanguage(nextLang);
localStorage.setItem('i18nextLng', nextLang);
// Trigger Google Translate widget
try {
const selectField = document.querySelector('.goog-te-combo') as HTMLSelectElement;
if (selectField) {
selectField.value = nextLang;
selectField.dispatchEvent(new Event('change'));
}
} catch (e) {
console.error('Google Translate trigger failed:', e);
}
};
// Sync dark mode class to HTML element
useEffect(() => {
console.log('[HeatTransPlan] Current Theme:', theme);
if (theme === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}, [theme]);
return (
<div className="app-shell">
{/* Top Navigation */}
<header className="top-nav">
<div className="nav-brand">
<span className="brand-text notranslate">HeatTransPlan</span>
<span className="brand-version notranslate">v2.1.0</span>
</div>
<nav className="nav-links">
{NAV_ITEMS.map((item) => (
<NavLink
key={item.path}
to={item.path}
className={({ isActive }) =>
`nav-item ${isActive ? 'active' : ''}`
}
end={item.path === '/'}
title={t(item.translationKey)}
>
<span className="nav-icon">{item.icon}</span>
<span className="nav-label">{t(item.translationKey)}</span>
</NavLink>
))}
</nav>
<div className="nav-actions">
<button className="theme-toggle" onClick={toggleLanguage} title={i18n.language === 'en' ? 'Switch to German' : 'Switch to English'}>
{i18n.language === 'en' ? 'π©πͺ' : 'π¬π§'}
</button>
<button className="theme-toggle" onClick={toggleTheme} title={theme === 'dark' ? t('appshell.theme.light') : t('appshell.theme.dark')}>
{theme === 'dark' ? 'βοΈ' : 'π'}
</button>
</div>
</header>
{/* Main content */}
<main className="main-content">
{children}
</main>
</div>
);
}
|