lolakd's picture
Создай полноценный frontend для проекта **LobsterTube** — полной копии YouTube, с современным дизайном, максимально приближённым к оригиналу YouTube (2025 года).
a7aae55 verified
tsx
import { Link, useNavigate, useSearchParams } from 'react-router-dom'
import { Menu, Search, Video, Bell, User, LogOut, Settings, Moon, Sun, Monitor } from 'lucide-react'
import { Button } from './ui/button'
import { Input } from './ui/input'
import { useUIStore } from '@/store/ui'
import { useAuthStore } from '@/store/auth'
import { useTheme } from '@/providers/ThemeProvider'
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from './ui/dropdown-menu'
import { useMemo } from 'react'
export default function Header() {
const navigate = useNavigate()
const [params, setParams] = useSearchParams()
const q = useMemo(() => params.get('q') || '', [params])
const { toggleSidebar } = useUIStore()
const { user, logout } = useAuthStore()
const { theme, setTheme } = useTheme()
function onSearch(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
const form = e.currentTarget
const data = new FormData(form)
const query = data.get('q') as string
navigate(`/search?q=${encodeURIComponent(query)}`)
}
return (
<header className="sticky top-0 z-50 border-b border-zinc-200/80 bg-white/80 backdrop-blur dark:border-zinc-800/80 dark:bg-zinc-950/80">
<div className="mx-auto flex h-14 max-w-[1920px] items-center gap-2 px-3 sm:px-5">
<div className="flex items-center gap-2">
<Button variant="ghost" size="icon" onClick={toggleSidebar} aria-label="Toggle menu">
<Menu className="h-5 w-5" />
</Button>
<Link to="/" className="flex items-center gap-2">
<div className="h-7 w-7 rounded-md bg-red-600 text-white flex items-center justify-center font-black">LT</div>
<span className="text-lg font-semibold tracking-tight">LobsterTube</span>
</Link>
</div>
<form onSubmit={onSearch} className="flex-1 flex justify-center px-2">
<div className="flex w-full max-w-2xl items-stretch">
<Input name="q" defaultValue={q} placeholder="Поиск" className="rounded-r-none border-r-0" />
<Button type="submit" className="rounded-l-none border border-l-0 border-zinc-200 dark:border-zinc-800">
<Search className="h-5 w-5" />
</Button>
</div>
</form>
<div className="flex items-center gap-1">
<Button variant="ghost" size="icon" onClick={() => navigate('/upload')} title="Создать">
<Video className="h-5 w-5" />
</Button>
<Button variant="ghost" size="icon">
<Bell className="h-5 w-5" />
</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="overflow-hidden">
{user ? (
<img src={user.avatarUrl || `https://api.dicebear.com/9.x/identicon/svg?seed=${user.id}`} className="h-7 w-7 rounded-full" alt="avatar" />
) : (
<User className="h-5 w-5" />
)}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-56">
{user ? (
<>
<div className="px-2 py-2 text-sm text-zinc-500 dark:text-zinc-400">Вошли как {user.name}</div>
<DropdownMenuItem onClick={() => navigate(`/channel/${user.id}`)}>
<User className="mr-2 h-4 w-4" /> Мой канал
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme('system')}>
<Monitor className="mr-2 h-4 w-4" /> Системная
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme('light')}>
<Sun className="mr-2 h-4 w-4" /> Светлая
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme('dark')}>
<Moon className="mr-2 h-4 w-4" /> Тёмная
</DropdownMenuItem>
<DropdownMenuItem>
<Settings className="mr-2 h-4 w-4" /> Настройки
</DropdownMenuItem>
<DropdownMenuItem onClick={() => logout()}>
<LogOut className="mr-2 h-4 w-4" /> Выйти
</DropdownMenuItem>
</>
) : (
<>
<DropdownMenuItem onClick={() => navigate('/login')}>
<User className="mr-2 h-4 w-4" /> Войти
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme('dark')}>
<Moon className="mr-2 h-4 w-4" /> Тёмная
</DropdownMenuItem>
</>
)}
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</header>
)
}
</html>