Initial skeleton: React/TS frontend + Go backend structure
This commit is contained in:
118
client/src/components/shared/AdminDrawer.tsx
Normal file
118
client/src/components/shared/AdminDrawer.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
import React from 'react'
|
||||
import { useCanvasStore } from '../../state/canvasStore'
|
||||
|
||||
interface AdminDrawerProps {
|
||||
open: boolean
|
||||
onClose: () => void
|
||||
users: Array<{
|
||||
userId: string
|
||||
name: string
|
||||
color: string
|
||||
status: string
|
||||
}>
|
||||
}
|
||||
|
||||
export const AdminDrawer: React.FC<AdminDrawerProps> = ({ open, onClose, users }) => {
|
||||
const { setCam } = useCanvasStore()
|
||||
|
||||
if (!open) return null
|
||||
|
||||
const handleSpectate = (userId: string) => {
|
||||
onClose()
|
||||
// In a real app, this would fly to the user's krate position
|
||||
console.log(`Spectating user: ${userId}`)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
width: '380px',
|
||||
zIndex: 56,
|
||||
background: 'rgba(13,17,24,.98)',
|
||||
borderLeft: '1px solid rgba(140,165,200,.2)',
|
||||
overflowY: 'auto',
|
||||
}}
|
||||
onClick={onClose}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
padding: '16px',
|
||||
borderBottom: '1px solid rgba(140,165,200,0.18)',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<h2 style={{ margin: 0, color: '#fff', fontSize: '16px' }}>Users</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
color: '#888',
|
||||
cursor: 'pointer',
|
||||
fontSize: '20px',
|
||||
}}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: '16px' }}>
|
||||
{users.map((user) => (
|
||||
<div
|
||||
key={user.userId}
|
||||
style={{
|
||||
marginBottom: '16px',
|
||||
padding: '12px',
|
||||
background: 'rgba(255,255,255,0.02)',
|
||||
borderRadius: '8px',
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
|
||||
<div
|
||||
style={{
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
borderRadius: '50%',
|
||||
background: user.color,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: '#fff',
|
||||
fontWeight: '600',
|
||||
}}
|
||||
>
|
||||
{user.name.slice(0, 2).toUpperCase()}
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<div style={{ color: '#fff', fontWeight: '600' }}>{user.name}</div>
|
||||
<div style={{ color: '#888', fontSize: '12px' }}>{user.status}</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleSpectate(user.userId)}
|
||||
style={{
|
||||
background: '#4dd6e8',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
padding: '6px 10px',
|
||||
color: '#000',
|
||||
fontSize: '12px',
|
||||
fontWeight: '600',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
Spectate
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user