moonlight-relay-server/src/App.tsx
2026-03-31 15:29:58 -04:00

86 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from "react";
import { useStatus } from "./hooks/useStatus";
import { StatusBar } from "./components/StatusBar";
import { HostCard } from "./components/HostCard";
import { AddHostModal } from "./components/AddHostModal";
export default function App() {
const { status, hosts, error, loading, refresh } = useStatus(3000);
const [showAddModal, setShowAddModal] = useState(false);
return (
<div className="flex flex-col h-screen bg-surface select-none">
{/* Title bar / drag region for Tauri */}
<div
data-tauri-drag-region
className="flex items-center justify-between px-4 py-3 bg-surface-raised"
style={{ WebkitAppRegion: "drag" } as React.CSSProperties}
>
<div className="flex items-center gap-2">
<span className="text-accent font-bold text-lg">🌙 Moonlight Relay</span>
</div>
<button
onClick={refresh}
style={{ WebkitAppRegion: "no-drag" } as React.CSSProperties}
className="text-gray-400 hover:text-white text-xs transition-colors"
title="Refresh hosts"
>
Refresh
</button>
</div>
{/* VPN + moonlight status */}
<StatusBar status={status} error={error} loading={loading} />
{/* Main content */}
<main className="flex-1 overflow-y-auto p-4">
{/* Host grid */}
{hosts.length === 0 && !loading ? (
<div className="flex flex-col items-center justify-center h-full gap-3 text-gray-500">
<span className="text-5xl">🔍</span>
<p className="text-sm">No hosts found yet.</p>
<p className="text-xs text-center max-w-xs">
Make sure Apollo/Artemis is running on your gaming PC and it's
reachable over Tailscale (or your local network).
</p>
<button
onClick={() => setShowAddModal(true)}
className="mt-2 px-4 py-2 rounded-lg bg-accent text-sm font-medium"
>
+ Add host manually
</button>
</div>
) : (
<>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3">
{hosts.map((h) => (
<HostCard key={h.name + h.ip} host={h} onRefresh={refresh} />
))}
{/* Add host card */}
<button
onClick={() => setShowAddModal(true)}
className="
flex flex-col items-center justify-center gap-2
p-5 rounded-xl border border-dashed border-surface-elevated
text-gray-500 hover:text-gray-300 hover:border-gray-500
transition-colors duration-150
"
>
<span className="text-2xl"></span>
<span className="text-xs">Add host</span>
</button>
</div>
</>
)}
</main>
{/* Add host modal */}
{showAddModal && (
<AddHostModal
onClose={() => setShowAddModal(false)}
onAdded={refresh}
/>
)}
</div>
);
}