diff options
Diffstat (limited to 'src/renderer')
| -rw-r--r-- | src/renderer/src/App.css | 64 | ||||
| -rw-r--r-- | src/renderer/src/components/Toolbar.tsx | 40 |
2 files changed, 97 insertions, 7 deletions
diff --git a/src/renderer/src/App.css b/src/renderer/src/App.css index 7f7b24c..906bf36 100644 --- a/src/renderer/src/App.css +++ b/src/renderer/src/App.css @@ -2229,6 +2229,10 @@ html, body, #root { /* ── Toolbar Users Count ─────────────────────────────────────── */ +.toolbar-users-wrap { + position: relative; +} + .toolbar-users { font-size: 11px; color: var(--text-muted); @@ -2236,6 +2240,66 @@ html, body, #root { padding: 2px 8px; border-radius: 10px; font-weight: 500; + border: none; + cursor: pointer; + font-family: var(--font-sans); +} + +.toolbar-users:hover { + background: var(--bg-active); +} + +.users-popover { + position: absolute; + top: calc(100% + 6px); + right: 0; + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: 6px; + padding: 6px 0; + min-width: 180px; + z-index: 100; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); +} + +.users-popover-title { + font-size: 10px; + font-weight: 600; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.5px; + padding: 4px 12px 6px; + border-bottom: 1px solid var(--border); + margin-bottom: 2px; +} + +.users-popover-item { + display: flex; + align-items: center; + gap: 8px; + padding: 5px 12px; + font-size: 12px; + color: var(--text-primary); +} + +.users-popover-dot { + width: 8px; + height: 8px; + border-radius: 50%; + flex-shrink: 0; +} + +.users-popover-name { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.users-popover-empty { + padding: 5px 12px; + font-size: 11px; + color: var(--text-muted); + font-style: italic; } /* ── Chat Panel ──────────────────────────────────────────────── */ diff --git a/src/renderer/src/components/Toolbar.tsx b/src/renderer/src/components/Toolbar.tsx index 0cee7e1..b89385a 100644 --- a/src/renderer/src/components/Toolbar.tsx +++ b/src/renderer/src/components/Toolbar.tsx @@ -3,6 +3,7 @@ import { useState, useRef, useEffect } from 'react' import { useAppStore } from '../stores/appStore' +import { remoteCursors } from '../App' interface ToolbarProps { onCompile: () => void @@ -19,19 +20,24 @@ export default function Toolbar({ onCompile, onLocalCompile, onBack }: ToolbarPr } = useAppStore() const [showCompileMenu, setShowCompileMenu] = useState(false) + const [showUsersPopover, setShowUsersPopover] = useState(false) const menuRef = useRef<HTMLDivElement>(null) + const usersRef = useRef<HTMLDivElement>(null) - // Close menu on outside click + // Close menus on outside click useEffect(() => { - if (!showCompileMenu) return + if (!showCompileMenu && !showUsersPopover) return const handler = (e: MouseEvent) => { - if (menuRef.current && !menuRef.current.contains(e.target as Node)) { + if (showCompileMenu && menuRef.current && !menuRef.current.contains(e.target as Node)) { setShowCompileMenu(false) } + if (showUsersPopover && usersRef.current && !usersRef.current.contains(e.target as Node)) { + setShowUsersPopover(false) + } } document.addEventListener('mousedown', handler) return () => document.removeEventListener('mousedown', handler) - }, [showCompileMenu]) + }, [showCompileMenu, showUsersPopover]) const projectName = overleafProject?.name || 'Project' @@ -91,9 +97,29 @@ export default function Toolbar({ onCompile, onLocalCompile, onBack }: ToolbarPr </div> <div className="toolbar-right"> {onlineUsersCount > 0 && ( - <span className="toolbar-users" title={`${onlineUsersCount} user${onlineUsersCount > 1 ? 's' : ''} online`}> - {onlineUsersCount} - </span> + <div className="toolbar-users-wrap" ref={usersRef}> + <button + className="toolbar-users" + onClick={() => setShowUsersPopover(!showUsersPopover)} + title={`${onlineUsersCount} user${onlineUsersCount > 1 ? 's' : ''} online`} + > + {onlineUsersCount} online + </button> + {showUsersPopover && ( + <div className="users-popover"> + <div className="users-popover-title">Online Users</div> + {Array.from(remoteCursors.values()).map((u) => ( + <div key={u.userId} className="users-popover-item"> + <span className="users-popover-dot" style={{ background: u.color }} /> + <span className="users-popover-name">{u.name}</span> + </div> + ))} + {remoteCursors.size === 0 && ( + <div className="users-popover-empty">No cursor data yet</div> + )} + </div> + )} + </div> )} <button className={`toolbar-btn ${showChat ? 'active' : ''}`} onClick={toggleChat} title="Toggle chat"> Chat |
