Fix UI — CSS variables, sidebar toggle with chevron, settings panel pushes content
This commit is contained in:
+43
-32
@@ -17,19 +17,26 @@ export default function Home() {
|
||||
setMessages,
|
||||
currentId,
|
||||
settingsOpen,
|
||||
setSettingsOpen,
|
||||
sidebarOpen,
|
||||
setSidebarOpen,
|
||||
} = useStore();
|
||||
|
||||
useEffect(() => {
|
||||
// Load settings from server
|
||||
api.getSettings().then(setSettings).catch(console.error);
|
||||
// Load conversations
|
||||
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(() => {
|
||||
// Load messages when conversation changes
|
||||
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 {
|
||||
@@ -38,51 +45,58 @@ export default function Home() {
|
||||
}, [currentId]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex h-dvh overflow-hidden"
|
||||
style={{ background: 'var(--bg)' }}
|
||||
data-theme={settings.theme}
|
||||
data-font={settings.font_size}
|
||||
>
|
||||
<div className="flex h-dvh overflow-hidden" style={{ background: 'var(--bg)' }}>
|
||||
|
||||
{/* Mobile sidebar overlay */}
|
||||
{sidebarOpen && (
|
||||
<div
|
||||
className="fixed inset-0 z-20 bg-black/40 md:hidden"
|
||||
className="fixed inset-0 z-20 md:hidden"
|
||||
style={{ background: 'rgba(0,0,0,0.4)' }}
|
||||
onClick={() => setSidebarOpen(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Sidebar */}
|
||||
{/* Sidebar — desktop: toggleable, mobile: slide-over */}
|
||||
<div
|
||||
className={`
|
||||
fixed inset-y-0 left-0 z-30 w-72 transform transition-transform duration-200
|
||||
md:relative md:translate-x-0 md:w-64 md:flex-shrink-0
|
||||
${sidebarOpen ? 'translate-x-0' : '-translate-x-full'}
|
||||
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: '1px solid var(--border)' }}
|
||||
style={{
|
||||
background: 'var(--sidebar-bg)',
|
||||
borderRight: sidebarOpen ? '1px solid var(--border)' : 'none',
|
||||
width: undefined,
|
||||
}}
|
||||
>
|
||||
<Sidebar />
|
||||
<div className="w-64 h-full">
|
||||
<Sidebar onClose={() => setSidebarOpen(false)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main */}
|
||||
<div className="flex flex-col flex-1 min-w-0">
|
||||
{/* 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">
|
||||
{/* Hamburger — mobile only */}
|
||||
{/* Sidebar toggle */}
|
||||
<button
|
||||
className="md:hidden p-1 rounded"
|
||||
style={{ color: 'var(--text3)' }}
|
||||
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="20" height="20" viewBox="0 0 20 20" fill="currentColor">
|
||||
<rect y="3" width="20" height="2" rx="1"/>
|
||||
<rect y="9" width="20" height="2" rx="1"/>
|
||||
<rect y="15" width="20" height="2" rx="1"/>
|
||||
<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)' }}>
|
||||
@@ -91,22 +105,19 @@ export default function Home() {
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => useStore.getState().setSettingsOpen(!settingsOpen)}
|
||||
style={{ color: 'var(--text3)', background: 'none', border: 'none', cursor: 'pointer', padding: '4px', borderRadius: '6px', fontSize: '18px' }}
|
||||
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>
|
||||
|
||||
{/* Messages */}
|
||||
<MessageList />
|
||||
|
||||
{/* Input */}
|
||||
<MessageInput />
|
||||
</div>
|
||||
|
||||
{/* Settings panel */}
|
||||
{/* Settings panel — pushes content, doesn't cover */}
|
||||
<SettingsPanel />
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user