generated from CubeCraft-Creations/Tracehound
RemoteRig: Core infrastructure — MQTT subscriber, Pi deployment, ESP32 firmware, hardware design #5
+54
-4
@@ -1,6 +1,19 @@
|
|||||||
import { Camera } from 'lucide-react'
|
import { Camera, Radio } from 'lucide-react'
|
||||||
|
import { useSSE } from './hooks/useSSE'
|
||||||
|
import { useCameraStore } from './store/useCameraStore'
|
||||||
|
import { CameraCard } from './components'
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
// Connect to SSE endpoint — auto-updates the camera store
|
||||||
|
useSSE()
|
||||||
|
|
||||||
|
// Subscribe to the camera store for reactivity.
|
||||||
|
// getCameras / getOnlineCount / getRecordingCount pull from live state.
|
||||||
|
const { getCameras, getOnlineCount, getRecordingCount } = useCameraStore()
|
||||||
|
const cameras = getCameras()
|
||||||
|
const onlineCount = getOnlineCount()
|
||||||
|
const recordingCount = getRecordingCount()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-rig-dark-900">
|
<div className="min-h-screen bg-rig-dark-900">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
@@ -14,21 +27,58 @@ function App() {
|
|||||||
<span className="ml-2 rounded-full bg-rig-accent/10 px-2.5 py-0.5 text-xs font-medium text-rig-accent">
|
<span className="ml-2 rounded-full bg-rig-accent/10 px-2.5 py-0.5 text-xs font-medium text-rig-accent">
|
||||||
Dashboard
|
Dashboard
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
{/* Stats badges */}
|
||||||
|
<div className="ml-auto flex items-center gap-4">
|
||||||
|
{/* Online count */}
|
||||||
|
<span
|
||||||
|
className="inline-flex items-center gap-1.5 rounded-full bg-rig-dark-700/60 px-3 py-1 text-xs font-medium text-rig-dark-200"
|
||||||
|
title="Cameras online"
|
||||||
|
>
|
||||||
|
<span className="h-2 w-2 rounded-full bg-rig-success" />
|
||||||
|
{onlineCount} online
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{/* Recording count */}
|
||||||
|
<span
|
||||||
|
className="inline-flex items-center gap-1.5 rounded-full bg-rig-dark-700/60 px-3 py-1 text-xs font-medium text-rig-dark-200"
|
||||||
|
title="Cameras recording"
|
||||||
|
>
|
||||||
|
<span className="relative flex h-2 w-2">
|
||||||
|
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-rig-danger opacity-75" />
|
||||||
|
<span className="relative inline-flex h-2 w-2 rounded-full bg-rig-danger" />
|
||||||
|
</span>
|
||||||
|
{recordingCount} recording
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* Main Content */}
|
{/* Main Content */}
|
||||||
<main className="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
|
<main className="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
|
||||||
|
{cameras.length === 0 ? (
|
||||||
|
/* Empty state */
|
||||||
<div className="flex flex-col items-center justify-center rounded-xl border border-dashed border-rig-dark-600 bg-rig-dark-800/30 py-24 text-center">
|
<div className="flex flex-col items-center justify-center rounded-xl border border-dashed border-rig-dark-600 bg-rig-dark-800/30 py-24 text-center">
|
||||||
<Camera className="mb-4 h-12 w-12 text-rig-dark-500" />
|
<span className="relative mb-4 inline-flex">
|
||||||
|
<Radio className="h-12 w-12 animate-pulse text-rig-accent" />
|
||||||
|
</span>
|
||||||
<h2 className="text-lg font-semibold text-rig-dark-200">
|
<h2 className="text-lg font-semibold text-rig-dark-200">
|
||||||
Dashboard Coming Soon
|
Waiting for cameras…
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-2 max-w-sm text-sm text-rig-dark-400">
|
<p className="mt-2 max-w-sm text-sm text-rig-dark-400">
|
||||||
Camera monitoring and remote control interface — under construction.
|
Connect cameras to your RemoteRig server and they will appear here
|
||||||
|
automatically.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
/* Camera grid */
|
||||||
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
||||||
|
{cameras.map((camera) => (
|
||||||
|
<CameraCard key={camera.camera_id} camera={camera} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
|
|||||||
Reference in New Issue
Block a user