OwnGPT.v2 / client /src /components /TopBar.jsx
parthib07's picture
Upload 199 files
212c959 verified
import { useState, useRef, useEffect } from 'react'
function RenameModal({ current, onSave, onClose }) {
const [val, setVal] = useState(current)
return (
<div className="modal-overlay" onClick={e => e.target === e.currentTarget && onClose()}>
<div className="modal-card" style={{ maxWidth: 360 }}>
<div className="modal-header">
<span className="modal-title">Rename Chat</span>
<button className="modal-close" onClick={onClose}>
<svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<div className="modal-body">
<input className="field-input" value={val} onChange={e => setVal(e.target.value)}
onKeyDown={e => e.key === 'Enter' && onSave(val)} autoFocus maxLength={80} />
</div>
<div className="modal-footer">
<button className="btn" onClick={onClose}>Cancel</button>
<button className="btn btn-primary" onClick={() => onSave(val)}>Save</button>
</div>
</div>
</div>
)
}
export default function TopBar({
onToggleSidebar, sessionTitle, user,
onRename, onLogin, onLogout, onFeedback, onSettings, theme, onTheme, currentSessionId,
}) {
const [dropOpen, setDropOpen] = useState(false)
const [renaming, setRenaming] = useState(false)
const dropRef = useRef(null)
useEffect(() => {
const h = e => { if (dropRef.current && !dropRef.current.contains(e.target)) setDropOpen(false) }
document.addEventListener('mousedown', h)
return () => document.removeEventListener('mousedown', h)
}, [])
const cycleTheme = () => onTheme(theme === 'dark' ? 'light' : 'dark')
const initial = user ? (user.username[0] || 'U').toUpperCase() : '?'
return (
<>
<div className="topbar">
<div className="topbar-left">
{/* Sidebar toggle */}
<button className="icon-btn" onClick={onToggleSidebar} title="Toggle sidebar">
<svg viewBox="0 0 24 24"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
</button>
<span className="session-title-display">{sessionTitle}</span>
{user && currentSessionId && (
<button className="icon-btn" onClick={() => setRenaming(true)} title="Rename">
<svg viewBox="0 0 24 24"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
</button>
)}
</div>
<div className="topbar-right">
{/* Theme toggle */}
<button className="icon-btn" onClick={cycleTheme} title={theme === 'dark' ? 'Switch to Light Mode' : 'Switch to Dark Mode'} style={{ transition: 'transform 0.4s var(--spring)' }}>
{theme === 'dark' ? (
<svg viewBox="0 0 24 24" style={{ transform: 'rotate(-20deg)' }}><path d="M21 12.79A9 9 0 1 1 11.21 3a7 7 0 0 0 9.79 9.79z"/></svg>
) : (
<svg viewBox="0 0 24 24" style={{ transform: 'rotate(90deg)' }}><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/></svg>
)}
</button>
{user ? (
<div className="avatar-menu" ref={dropRef}>
<button
className="avatar-btn"
onClick={() => setDropOpen(o => !o)}
title="Account"
style={user.avatar_url ? { backgroundImage: `url(${user.avatar_url})`, backgroundSize: 'cover', backgroundPosition: 'center', color: 'transparent' } : {}}
>
{!user.avatar_url && initial}
<span className="avatar-online" />
</button>
{dropOpen && (
<div className="avatar-dropdown">
<div className="avd-user">
<div className="avd-name">{user.username}</div>
<div className="avd-sub">Free Plan</div>
</div>
<div className="avd-sep" />
<button className="avd-item" onClick={() => { setDropOpen(false); onSettings() }}>
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14M4.93 4.93a10 10 0 0 0 0 14.14"/></svg>
Settings
</button>
<button className="avd-item" onClick={() => { setDropOpen(false); onFeedback() }}>
<svg viewBox="0 0 24 24"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
Send Feedback
</button>
<div className="avd-sep" />
<button className="avd-item danger" onClick={() => { setDropOpen(false); onLogout() }}>
<svg viewBox="0 0 24 24"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
Sign Out
</button>
</div>
)}
</div>
) : (
<button className="btn btn-primary" onClick={onLogin}>Sign In</button>
)}
</div>
</div>
{renaming && (
<RenameModal
current={sessionTitle}
onSave={t => { onRename(t); setRenaming(false) }}
onClose={() => setRenaming(false)}
/>
)}
</>
)
}