import { Head, Link, usePage } from '@inertiajs/react'; import { ArrowRight, Compass, LayoutDashboard, Radio, Search, UserPlus, Users, Video, } from 'lucide-react'; import { useMemo, useState } from 'react'; import { LanguageSwitcher } from '@/components/language-switcher'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { useTranslation } from '@/lib/translations'; import { cn } from '@/lib/utils'; import { dashboard, home, login, register } from '@/routes'; import { show as showChannel } from '@/routes/channels'; import type { ChannelCard, ChannelCategory } from '@/types'; type Props = { canRegister: boolean; liveChannels: ChannelCard[]; categories: ChannelCategory[]; }; export default function Welcome({ canRegister, liveChannels, categories, }: Props) { const { auth } = usePage().props; const { t } = useTranslation(); const [query, setQuery] = useState(''); const [category, setCategory] = useState('all'); const featuredChannel = liveChannels[0] ?? null; const filteredChannels = useMemo(() => { const normalizedQuery = query.trim().toLowerCase(); return liveChannels.filter((channel) => { const matchesCategory = category === 'all' || channel.category?.value === category; const matchesQuery = normalizedQuery === '' || channel.display_name.toLowerCase().includes(normalizedQuery) || channel.broadcast?.title .toLowerCase() .includes(normalizedQuery) || channel.owner.name.toLowerCase().includes(normalizedQuery); return matchesCategory && matchesQuery; }); }, [category, liveChannels, query]); return ( <>
Nyone
{auth.user ? ( ) : ( <> {canRegister && ( )} )}
{featuredChannel ? (

{featuredChannel.broadcast ?.title ?? featuredChannel.display_name}

{featuredChannel.description ?? t( ':channel is live now with :count viewers.', { channel: featuredChannel.display_name, count: featuredChannel.viewer_count, }, )}

{featuredChannel.display_name} {featuredChannel.category ?.label ?? t('Uncategorized')} {t(':count viewers', { count: featuredChannel.viewer_count, })} {t('Watch')}
) : (

{t('The live floor is quiet')}

{t( 'Creators can prepare a broadcast in the studio and go live from OBS when ready.', )}

)}

{t('Live directory')}

{t( 'Browse active channels by category or title.', )}

setQuery(event.target.value) } placeholder={t('Search live channels')} className="ps-9 sm:w-72" />
{filteredChannels.length > 0 ? (
{filteredChannels.map((channel) => ( ))}
) : (
{t('No streams match this view')}
{t( 'Clear search or switch categories.', )}
)}
); } function StreamCard({ channel }: { channel: ChannelCard }) { const { t } = useTranslation(); return (
{channel.broadcast?.title ?? channel.display_name}
{t(':channel by :owner', { channel: channel.display_name, owner: channel.owner.name, })}
{channel.category?.label ?? t('Uncategorized')} {t(':count viewers', { count: channel.viewer_count, })}
); } function Thumbnail({ channel, className, label = 'Live preview', }: { channel: ChannelCard; className?: string; label?: string; }) { const { t } = useTranslation(); return (
{channel.thumbnail_url ? ( ) : (
{t(label)}
)}
); } function LiveBadge({ compact = false }: { compact?: boolean }) { const { t } = useTranslation(); return ( {t('LIVE')} ); } function Metric({ icon: Icon, label, value, }: { icon: typeof Radio; label: string; value: string; }) { return (
{label}
{value}
); }