105 lines
4.0 KiB
TypeScript
105 lines
4.0 KiB
TypeScript
|
|
import React, { useState } from 'react'
|
||
|
|
import { AppBar, Toolbar, IconButton, Typography, Button, Menu, MenuItem, Box, Chip, TextField } from '@mui/material'
|
||
|
|
import MenuIcon from '@mui/icons-material/Menu'
|
||
|
|
import SettingsIcon from '@mui/icons-material/Settings'
|
||
|
|
import StorageIcon from '@mui/icons-material/Storage'
|
||
|
|
import { useServers } from '../context/ServersContext'
|
||
|
|
|
||
|
|
type HeaderProps = {
|
||
|
|
onOpenSettings?: () => void
|
||
|
|
onToggleSidebar?: () => void
|
||
|
|
searchQuery?: string
|
||
|
|
onSearchQueryChange?: (value: string) => void
|
||
|
|
searchDisabled?: boolean
|
||
|
|
}
|
||
|
|
|
||
|
|
export default function Header({ onOpenSettings, onToggleSidebar, searchQuery = '', onSearchQueryChange, searchDisabled = false }: HeaderProps) {
|
||
|
|
const { servers, activeServerId, setActiveServerId } = useServers()
|
||
|
|
const [anchor, setAnchor] = useState<HTMLElement | null>(null)
|
||
|
|
|
||
|
|
const active = servers.find((s) => s.id === activeServerId)
|
||
|
|
const activeServerLabel = active ? active.name || active.host : 'No server configured'
|
||
|
|
|
||
|
|
const handleOpen = (e: React.MouseEvent<HTMLElement>) => setAnchor(e.currentTarget)
|
||
|
|
const handleClose = () => setAnchor(null)
|
||
|
|
|
||
|
|
return (
|
||
|
|
<AppBar position="static" color="transparent" elevation={0} sx={{ mb: 0, borderBottom: '1px solid rgba(255,255,255,0.04)' }}>
|
||
|
|
<Toolbar variant="dense" sx={{ minHeight: { xs: 'auto', sm: 48 }, py: { xs: 1, sm: 0.25 }, gap: 1, flexWrap: { xs: 'wrap', sm: 'nowrap' } }}>
|
||
|
|
<IconButton onClick={() => onToggleSidebar && onToggleSidebar()} aria-label="menu" size="medium" sx={{ flexShrink: 0 }}>
|
||
|
|
<MenuIcon />
|
||
|
|
</IconButton>
|
||
|
|
|
||
|
|
<TextField
|
||
|
|
value={searchQuery}
|
||
|
|
onChange={(event) => onSearchQueryChange && onSearchQueryChange(event.target.value)}
|
||
|
|
disabled={searchDisabled}
|
||
|
|
size="small"
|
||
|
|
placeholder="Search library"
|
||
|
|
sx={{
|
||
|
|
flex: { xs: '1 1 calc(100% - 104px)', sm: 1 },
|
||
|
|
minWidth: 0,
|
||
|
|
maxWidth: { sm: 520 },
|
||
|
|
order: { xs: 1, sm: 0 },
|
||
|
|
'& .MuiInputBase-input': { fontSize: { xs: 14, sm: 13 }, py: 0.9 },
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
|
||
|
|
<IconButton onClick={() => onOpenSettings && onOpenSettings()} aria-label="settings" size="medium" sx={{ width: 40, height: 40, flexShrink: 0, order: { xs: 2, sm: 0 } }}>
|
||
|
|
<SettingsIcon sx={{ fontSize: 20 }} />
|
||
|
|
</IconButton>
|
||
|
|
|
||
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, width: { xs: '100%', sm: 'auto' }, minWidth: 0, order: { xs: 3, sm: 0 } }}>
|
||
|
|
<Button
|
||
|
|
variant="text"
|
||
|
|
onClick={handleOpen}
|
||
|
|
startIcon={<StorageIcon sx={{ fontSize: 18 }} />}
|
||
|
|
sx={{
|
||
|
|
px: 0.75,
|
||
|
|
py: 0.25,
|
||
|
|
fontSize: { xs: 13, sm: 13 },
|
||
|
|
justifyContent: 'flex-start',
|
||
|
|
minWidth: 0,
|
||
|
|
flex: { xs: 1, sm: '0 1 auto' },
|
||
|
|
overflow: 'hidden',
|
||
|
|
whiteSpace: 'nowrap',
|
||
|
|
textOverflow: 'ellipsis',
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
{activeServerLabel}
|
||
|
|
</Button>
|
||
|
|
{active?.lastTest && active.lastTest.ok === false && (
|
||
|
|
<Chip label={active.lastTest.message} color="error" size="small" sx={{ maxWidth: { xs: 132, sm: 200 } }} />
|
||
|
|
)}
|
||
|
|
<Menu anchorEl={anchor} open={Boolean(anchor)} onClose={handleClose}>
|
||
|
|
{servers.length === 0 ? (
|
||
|
|
<MenuItem disabled>No servers configured</MenuItem>
|
||
|
|
) : (
|
||
|
|
servers.map((s) => (
|
||
|
|
<MenuItem
|
||
|
|
key={s.id}
|
||
|
|
selected={s.id === activeServerId}
|
||
|
|
onClick={() => {
|
||
|
|
setActiveServerId(s.id)
|
||
|
|
handleClose()
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
{s.name || s.host}
|
||
|
|
</MenuItem>
|
||
|
|
))
|
||
|
|
)}
|
||
|
|
<MenuItem
|
||
|
|
onClick={() => {
|
||
|
|
handleClose()
|
||
|
|
onOpenSettings && onOpenSettings()
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
Manage servers...
|
||
|
|
</MenuItem>
|
||
|
|
</Menu>
|
||
|
|
</Box>
|
||
|
|
</Toolbar>
|
||
|
|
</AppBar>
|
||
|
|
)
|
||
|
|
}
|