Initial commit
This commit is contained in:
200
components/viewer/toolbar.tsx
Normal file
200
components/viewer/toolbar.tsx
Normal file
@@ -0,0 +1,200 @@
|
||||
'use client'
|
||||
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
import {
|
||||
Maximize2,
|
||||
Minimize2,
|
||||
Monitor,
|
||||
Volume2,
|
||||
VolumeX,
|
||||
Settings,
|
||||
X,
|
||||
RefreshCw,
|
||||
Signal,
|
||||
SignalLow,
|
||||
SignalMedium,
|
||||
Keyboard,
|
||||
MousePointer2,
|
||||
Loader2,
|
||||
CheckCircle2
|
||||
} from 'lucide-react'
|
||||
|
||||
interface Session {
|
||||
id: string
|
||||
machine_id: string | null
|
||||
machine_name: string | null
|
||||
started_at: string
|
||||
}
|
||||
|
||||
type ConnectionState = 'connecting' | 'connected' | 'disconnected' | 'error'
|
||||
|
||||
interface ViewerToolbarProps {
|
||||
session: Session | null
|
||||
connectionState: ConnectionState
|
||||
isFullscreen: boolean
|
||||
quality: 'high' | 'medium' | 'low'
|
||||
isMuted: boolean
|
||||
onToggleFullscreen: () => void
|
||||
onQualityChange: (quality: 'high' | 'medium' | 'low') => void
|
||||
onToggleMute: () => void
|
||||
onDisconnect: () => void
|
||||
onReconnect: () => void
|
||||
}
|
||||
|
||||
export function ViewerToolbar({
|
||||
session,
|
||||
connectionState,
|
||||
isFullscreen,
|
||||
quality,
|
||||
isMuted,
|
||||
onToggleFullscreen,
|
||||
onQualityChange,
|
||||
onToggleMute,
|
||||
onDisconnect,
|
||||
onReconnect,
|
||||
}: ViewerToolbarProps) {
|
||||
const getQualityIcon = () => {
|
||||
switch (quality) {
|
||||
case 'high': return Signal
|
||||
case 'medium': return SignalMedium
|
||||
case 'low': return SignalLow
|
||||
}
|
||||
}
|
||||
|
||||
const getConnectionBadge = () => {
|
||||
switch (connectionState) {
|
||||
case 'connecting':
|
||||
return (
|
||||
<span className="flex items-center gap-2 text-yellow-500">
|
||||
<Loader2 className="h-3 w-3 animate-spin" />
|
||||
Connecting
|
||||
</span>
|
||||
)
|
||||
case 'connected':
|
||||
return (
|
||||
<span className="flex items-center gap-2 text-green-500">
|
||||
<span className="h-2 w-2 rounded-full bg-green-500" />
|
||||
Connected
|
||||
</span>
|
||||
)
|
||||
case 'disconnected':
|
||||
return (
|
||||
<span className="flex items-center gap-2 text-muted-foreground">
|
||||
<span className="h-2 w-2 rounded-full bg-muted-foreground" />
|
||||
Disconnected
|
||||
</span>
|
||||
)
|
||||
case 'error':
|
||||
return (
|
||||
<span className="flex items-center gap-2 text-destructive">
|
||||
<span className="h-2 w-2 rounded-full bg-destructive" />
|
||||
Error
|
||||
</span>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const QualityIcon = getQualityIcon()
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between h-12 px-4 bg-card/95 backdrop-blur border-b border-border/50">
|
||||
{/* Left section */}
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Monitor className="h-4 w-4 text-primary" />
|
||||
<span className="font-medium text-sm">
|
||||
{session?.machine_name || 'Remote Machine'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-sm">
|
||||
{getConnectionBadge()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right section */}
|
||||
<div className="flex items-center gap-1">
|
||||
{/* Input indicators */}
|
||||
<div className="flex items-center gap-2 px-3 border-r border-border/50 mr-2">
|
||||
<MousePointer2 className="h-4 w-4 text-muted-foreground" />
|
||||
<Keyboard className="h-4 w-4 text-muted-foreground" />
|
||||
</div>
|
||||
|
||||
{/* Quality selector */}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="h-8 w-8">
|
||||
<QualityIcon className="h-4 w-4" />
|
||||
<span className="sr-only">Quality</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuLabel>Stream Quality</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => onQualityChange('high')}>
|
||||
<Signal className="mr-2 h-4 w-4" />
|
||||
High
|
||||
{quality === 'high' && <CheckCircle2 className="ml-auto h-4 w-4 text-primary" />}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => onQualityChange('medium')}>
|
||||
<SignalMedium className="mr-2 h-4 w-4" />
|
||||
Medium
|
||||
{quality === 'medium' && <CheckCircle2 className="ml-auto h-4 w-4 text-primary" />}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => onQualityChange('low')}>
|
||||
<SignalLow className="mr-2 h-4 w-4" />
|
||||
Low
|
||||
{quality === 'low' && <CheckCircle2 className="ml-auto h-4 w-4 text-primary" />}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
{/* Mute toggle */}
|
||||
<Button variant="ghost" size="icon" className="h-8 w-8" onClick={onToggleMute}>
|
||||
{isMuted ? (
|
||||
<VolumeX className="h-4 w-4" />
|
||||
) : (
|
||||
<Volume2 className="h-4 w-4" />
|
||||
)}
|
||||
<span className="sr-only">{isMuted ? 'Unmute' : 'Mute'}</span>
|
||||
</Button>
|
||||
|
||||
{/* Fullscreen toggle */}
|
||||
<Button variant="ghost" size="icon" className="h-8 w-8" onClick={onToggleFullscreen}>
|
||||
{isFullscreen ? (
|
||||
<Minimize2 className="h-4 w-4" />
|
||||
) : (
|
||||
<Maximize2 className="h-4 w-4" />
|
||||
)}
|
||||
<span className="sr-only">{isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}</span>
|
||||
</Button>
|
||||
|
||||
{/* Reconnect */}
|
||||
{connectionState === 'disconnected' && (
|
||||
<Button variant="ghost" size="icon" className="h-8 w-8" onClick={onReconnect}>
|
||||
<RefreshCw className="h-4 w-4" />
|
||||
<span className="sr-only">Reconnect</span>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* Disconnect */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 text-destructive hover:text-destructive hover:bg-destructive/10"
|
||||
onClick={onDisconnect}
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Disconnect</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user