69 lines
2.4 KiB
TypeScript
69 lines
2.4 KiB
TypeScript
import React from 'react';
|
|
import { Radio } from 'lucide-react';
|
|
import { api, Stream } from '@/lib/api';
|
|
import StreamCard from '../components/StreamCard';
|
|
|
|
import type { Metadata } from 'next';
|
|
|
|
export const metadata: Metadata = {
|
|
title: 'Live Cams',
|
|
description: 'Watch live wildlife cameras streaming 24/7 from Cape Coral.',
|
|
};
|
|
|
|
|
|
|
|
async function getStreams(): Promise<Stream[]> {
|
|
try { return await api.getStreams(); }
|
|
catch { return []; }
|
|
}
|
|
|
|
export default async function StreamsPage() {
|
|
const streams = await getStreams();
|
|
const live = streams.filter((s) => s.status === 'live');
|
|
const offline = streams.filter((s) => s.status !== 'live');
|
|
|
|
return (
|
|
<div className="max-w-7xl mx-auto px-6 py-16 space-y-16">
|
|
<header className="space-y-3">
|
|
<div className="flex items-center gap-2 text-red-400 text-sm font-bold uppercase tracking-widest">
|
|
<span className="w-2 h-2 rounded-full bg-red-500 animate-pulse" />
|
|
{live.length} camera{live.length !== 1 ? 's' : ''} live now
|
|
</div>
|
|
<h1 className="text-4xl font-black text-white">Wildlife Cameras</h1>
|
|
<p className="text-stone-400 text-lg max-w-2xl">
|
|
Free, 24/7 livestreams from Cape Coral's burrowing owl habitats and wildlife areas.
|
|
</p>
|
|
</header>
|
|
|
|
{streams.length === 0 && (
|
|
<div className="flex flex-col items-center justify-center py-32 space-y-4 text-stone-500">
|
|
<Radio size={48} className="text-stone-600" />
|
|
<p className="text-lg font-semibold">No cameras available</p>
|
|
<p className="text-sm">Check back soon or ensure the backend is running.</p>
|
|
</div>
|
|
)}
|
|
|
|
{live.length > 0 && (
|
|
<section className="space-y-6">
|
|
<h2 className="text-xl font-bold text-white flex items-center gap-2">
|
|
<span className="w-2 h-2 rounded-full bg-red-500 animate-pulse" />
|
|
Live Now
|
|
</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
{live.map((s) => <StreamCard key={s.id} stream={s} />)}
|
|
</div>
|
|
</section>
|
|
)}
|
|
|
|
{offline.length > 0 && (
|
|
<section className="space-y-6">
|
|
<h2 className="text-xl font-bold text-stone-400">Offline Cameras</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 opacity-70">
|
|
{offline.map((s) => <StreamCard key={s.id} stream={s} />)}
|
|
</div>
|
|
</section>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|