Files
hermes-mobile/apps/mobile/src/components/app-shell/AppShell.tsx
T
2026-07-09 04:57:47 +00:00

71 lines
2.5 KiB
TypeScript

import { useEffect, useMemo, useState, type ReactNode } from 'react';
import { Flame, Gem, Heart, Wifi, WifiOff } from 'lucide-react';
import { useCompanion } from '../../api/CompanionContext.js';
import type { ScreenId } from '../../app/navigation.js';
import { BottomNav } from '../bottom-nav/BottomNav.js';
type AppShellProps = {
activeScreen: ScreenId;
children: ReactNode;
onNavigate: (screen: ScreenId) => void;
};
const screenTitles: Record<ScreenId, { title: string; kicker: string }> = {
chat: { title: 'Quest', kicker: 'Hermes training path' },
files: { title: 'Backpack', kicker: 'Workspace loot' },
terminal: { title: 'Power move', kicker: 'Run a command' },
activity: { title: 'League', kicker: 'Companion stats' },
settings: { title: 'Nest', kicker: 'Connection setup' },
};
export function AppShell({ activeScreen, children, onNavigate }: AppShellProps) {
const { client } = useCompanion();
const [online, setOnline] = useState(false);
useEffect(() => {
let cancelled = false;
client
.health()
.then(() => {
if (!cancelled) setOnline(true);
})
.catch(() => {
if (!cancelled) setOnline(false);
});
return () => {
cancelled = true;
};
}, [client]);
const title = useMemo(() => screenTitles[activeScreen], [activeScreen]);
return (
<div className="phone-app">
<div className="app-shell">
<header className="app-header">
<div className="avatar-badge" aria-hidden="true"></div>
<div className="app-header__copy">
<p className="eyebrow">{title.kicker}</p>
<h1>{title.title}</h1>
</div>
<div className="top-stats" aria-label="Hermes status summary">
<span className="stat-chip stat-chip--fire"><Flame size={16} fill="currentColor" />7</span>
<span className="stat-chip stat-chip--gem"><Gem size={16} fill="currentColor" />550</span>
<span className="stat-chip stat-chip--heart"><Heart size={16} fill="currentColor" />3</span>
</div>
</header>
<div className={`connection-banner ${online ? 'connection-banner--online' : ''}`}>
{online ? <Wifi size={18} /> : <WifiOff size={18} />}
<span>{online ? 'Companion online — ready for quests' : 'Companion offline — check Settings'}</span>
</div>
<main className="app-main">{children}</main>
<BottomNav activeScreen={activeScreen} onNavigate={onNavigate} />
</div>
</div>
);
}