/**
* App.jsx — Saltybot Social Dashboard root component.
*
* Layout:
* [TopBar: connection config + pipeline state badge]
* [TabNav: Status | Faces | Conversation | Personality | Navigation]
* [TabContent]
*/
import { useState, useCallback } from 'react';
import { useRosbridge } from './hooks/useRosbridge.js';
import { StatusPanel } from './components/StatusPanel.jsx';
import { FaceGallery } from './components/FaceGallery.jsx';
import { ConversationLog } from './components/ConversationLog.jsx';
import { PersonalityTuner } from './components/PersonalityTuner.jsx';
import { NavModeSelector } from './components/NavModeSelector.jsx';
const TABS = [
{ id: 'status', label: 'Status', icon: '⬤' },
{ id: 'faces', label: 'Faces', icon: '◉' },
{ id: 'conversation', label: 'Conversation', icon: '◌' },
{ id: 'personality', label: 'Personality', icon: '◈' },
{ id: 'navigation', label: 'Navigation', icon: '◫' },
];
const DEFAULT_WS_URL = 'ws://localhost:9090';
function ConnectionBar({ url, setUrl, connected, error }) {
const [editing, setEditing] = useState(false);
const [draft, setDraft] = useState(url);
const handleApply = () => {
setUrl(draft);
setEditing(false);
};
return (
{/* Connection dot */}
{editing ? (
setDraft(e.target.value)}
onKeyDown={(e) => { if (e.key === 'Enter') handleApply(); if (e.key === 'Escape') setEditing(false); }}
autoFocus
className="bg-gray-900 border border-cyan-800 rounded px-2 py-0.5 text-cyan-300 w-52 focus:outline-none"
/>
) : (
)}
);
}
export default function App() {
const [wsUrl, setWsUrl] = useState(DEFAULT_WS_URL);
const [activeTab, setActiveTab] = useState('status');
const { connected, error, subscribe, publish, callService, setParam } = useRosbridge(wsUrl);
// Memoized publish for NavModeSelector (avoids recreating on every render)
const publishFn = useCallback(
(name, type, data) => publish(name, type, data),
[publish]
);
return (
{/* ── Top Bar ── */}
{/* ── Tab Nav ── */}
{/* ── Content ── */}
{activeTab === 'status' && (
)}
{activeTab === 'faces' && (
)}
{activeTab === 'conversation' && (
)}
{activeTab === 'personality' && (
)}
{activeTab === 'navigation' && (
)}
{/* ── Footer ── */}
);
}