Neon:ryan
Refactor Canvas components and enhance user experience
2dc7022
Raw
History Blame Contribute Delete
3.91 kB
import React from 'react';
import { Home, Menu, Users } from 'lucide-react';
import ThemeToggle from './ThemeToggle';
import { useAppConfig } from '../contexts/AppConfigContext';
/**
* Shared floating header used on every page so the app feels like one surface.
*
* Props:
* currentPage: 'home' | 'chat' | 'canvas'
* onNavigateToHome, onNavigateToChat, onNavigateToCanvas: navigation callbacks
* (onNavigateToCanvas may receive 'insights' | 'workspace' to deep-link a view)
* onMobileMenu?: () => void — when present, shows the mobile menu button
* children?: ReactNode — extra controls slotted between the tabs and the theme toggle
*/
const AppHeader = ({
currentPage = 'home',
onNavigateToHome,
onNavigateToChat,
onNavigateToCanvas,
onMobileMenu,
children,
}) => {
const { config, resolveIcon } = useAppConfig();
const BrandIcon = resolveIcon ? resolveIcon('Users') : Users;
const goToCanvas = (view) => {
if (onNavigateToCanvas) onNavigateToCanvas(view);
};
// Accept either 'canvas' (all canvas tabs highlight equally) or a more specific
// 'canvas-<subview>' from CanvasPage so only the active one highlights.
const isOnHome = currentPage === 'home';
const isOnChat = currentPage === 'chat';
const isOnCanvas = currentPage === 'canvas' || currentPage.startsWith('canvas-');
const canvasSub = currentPage.startsWith('canvas-') ? currentPage.slice(7) : null;
const tabActive = (sub) => isOnCanvas && (canvasSub === null ? false : canvasSub === sub);
return (
<header className="floating-header app-header">
<div className="header-left">
{onMobileMenu && (
<button className="mobile-menu-button" onClick={onMobileMenu}>
<Menu size={20} />
</button>
)}
<button
className="modern-home-btn"
onClick={onNavigateToHome}
title="Home"
disabled={isOnHome}
aria-disabled={isOnHome}
>
<Home size={20} />
</button>
<div className="header-brand">
<div className="brand-icon">
<BrandIcon size={24} />
</div>
<div className="brand-text">
<h1>{config?.app?.title || 'Advisory'}</h1>
<p>{config?.app?.subtitle || 'AI-Powered Guidance'}</p>
</div>
</div>
</div>
{/* Hide the view pill bar on the home page — home is a landing page,
not part of the chat ↔ canvas surface. */}
{!isOnHome && (
<div className="canvas-tabs chat-view-tabs">
<button className={`tab ${isOnChat ? 'active' : ''}`} onClick={onNavigateToChat}>Chat</button>
<button className={`tab ${tabActive('insights') ? 'active' : ''}`} onClick={() => goToCanvas('insights')}>Insights</button>
<button className={`tab ${tabActive('workspace') ? 'active' : ''}`} onClick={() => goToCanvas('workspace')}>Workspace</button>
<button className={`tab ${tabActive('deliverables') ? 'active' : ''}`} onClick={() => goToCanvas('deliverables')}>Documents</button>
</div>
)}
{/* Compact mobile dropdown — appears in place of the pill bar at narrow widths */}
{!isOnHome && (
<select
className="canvas-tabs-mobile"
value={isOnChat ? 'chat' : (canvasSub || 'workspace')}
onChange={(e) => {
const v = e.target.value;
if (v === 'chat') onNavigateToChat();
else goToCanvas(v);
}}
>
<option value="chat">Chat</option>
<option value="insights">Insights</option>
<option value="workspace">Workspace</option>
<option value="deliverables">Documents</option>
</select>
)}
<div className="header-right">
{children}
<ThemeToggle />
</div>
</header>
);
};
export default AppHeader;