Files
aaronai-web/app/page.tsx
T

125 lines
4.2 KiB
TypeScript

'use client';
import { useEffect } from 'react';
import { useStore } from '@/lib/store';
import { api } from '@/lib/api';
import Sidebar from '@/components/Sidebar';
import MessageList from '@/components/MessageList';
import MessageInput from '@/components/MessageInput';
import SettingsPanel from '@/components/SettingsPanel';
export default function Home() {
const {
settings,
setSettings,
setConversations,
setCurrentId,
setMessages,
currentId,
settingsOpen,
setSettingsOpen,
sidebarOpen,
setSidebarOpen,
} = useStore();
useEffect(() => {
api.getSettings().then(s => {
setSettings(s);
document.documentElement.setAttribute('data-theme', s.theme || 'light');
document.documentElement.setAttribute('data-font', s.font_size || 'medium');
}).catch(console.error);
api.getConversations().then(setConversations).catch(console.error);
}, []);
useEffect(() => {
document.documentElement.setAttribute('data-theme', settings.theme || 'light');
document.documentElement.setAttribute('data-font', settings.font_size || 'medium');
}, [settings.theme, settings.font_size]);
useEffect(() => {
if (currentId) {
api.getMessages(currentId).then(setMessages).catch(console.error);
} else {
setMessages([]);
}
}, [currentId]);
return (
<div className="flex h-dvh overflow-hidden" style={{ background: 'var(--bg)' }}>
{/* Mobile sidebar overlay */}
{sidebarOpen && (
<div
className="fixed inset-0 z-20 md:hidden"
style={{ background: 'rgba(0,0,0,0.4)' }}
onClick={() => setSidebarOpen(false)}
/>
)}
{/* Sidebar — desktop: toggleable, mobile: slide-over */}
<div
className={`
fixed inset-y-0 left-0 z-30 flex-shrink-0 transition-all duration-200
md:relative md:translate-x-0
${sidebarOpen ? 'translate-x-0 w-64' : '-translate-x-full md:translate-x-0'}
${sidebarOpen ? 'md:w-64' : 'md:w-0 md:overflow-hidden'}
`}
style={{
background: 'var(--sidebar-bg)',
borderRight: sidebarOpen ? '1px solid var(--border)' : 'none',
width: undefined,
}}
>
<div className="w-64 h-full">
<Sidebar onClose={() => setSidebarOpen(false)} />
</div>
</div>
{/* Main — shrinks when settings opens */}
<div
className="flex flex-col flex-1 min-w-0 transition-all duration-200"
style={{ marginRight: settingsOpen ? '340px' : '0' }}
>
{/* Topbar */}
<div
className="flex items-center justify-between px-4 py-3 flex-shrink-0"
style={{ borderBottom: '1px solid var(--border)' }}
>
<div className="flex items-center gap-3">
{/* Sidebar toggle */}
<button
onClick={() => setSidebarOpen(!sidebarOpen)}
style={{ color: 'var(--text3)', background: 'none', border: 'none', cursor: 'pointer', padding: '4px', borderRadius: '6px', lineHeight: 1 }}
aria-label="Toggle sidebar"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
{sidebarOpen
? <polyline points="15 18 9 12 15 6" />
: <polyline points="9 18 15 12 9 6" />
}
</svg>
</button>
<span style={{ fontSize: '13px', color: 'var(--text3)' }}>
<strong style={{ color: 'var(--text)', fontWeight: 500 }}>Aaron AI</strong>
{' '} personal knowledge assistant
</span>
</div>
<button
onClick={() => setSettingsOpen(!settingsOpen)}
style={{ color: settingsOpen ? 'var(--accent)' : 'var(--text3)', background: 'none', border: 'none', cursor: 'pointer', padding: '4px', borderRadius: '6px', fontSize: '18px' }}
aria-label="Settings"
>
</button>
</div>
<MessageList />
<MessageInput />
</div>
{/* Settings panel — pushes content, doesn't cover */}
<SettingsPanel />
</div>
);
}