UI gaps: radio player widget, logo generator, public room page

Phase D of the parity push:
- Radio player: fixed bottom-right widget (port of atom's radio-player.blade)
  that streams the hotel radio via <audio>, with play/pause, volume, current
  DJ / now-playing and live listener count, polling the public API every 15s.
  A server gate (RadioPlayerGate) only mounts it when radio is enabled + a
  stream URL is set, so no widget JS ships when off. Mounted in the layout.
- Logo generator (/logo): client tool — hotel name + font/colour/size pickers
  with a live preview and "download PNG" via canvas.
- Public room page (/room/[id]): renders an emulator room (name, owner,
  users/max, state, category) in a ContentCard.

Verified live (prod, amx_test): /logo renders the generator, /room/50 shows
the real room "Dark Elegant Bundle", and with radio enabled the player
mounts fixed bottom-right (audio + play/pause + Test FM); reverted the test
settings. tsc 0, vitest 49/49, next build 0.
This commit is contained in:
Simo committed 2026-06-28 21:48:42 +02:00
1 parent 80f591a343
commit 8cedf5614e
4 files changed
+426

No files matched your search

+24
View File
@@ -0,0 +1,24 @@
import { ContentCard } from "@/components/public/ui";
import LogoGenerator from "@/components/public/logo-generator";
export const metadata = { title: "Logo generator" };
/**
* Public logo generator (AtomCMS logo-generator.blade). Server wrapper that
* renders the atom-styled ContentCard header and hands off to the fully
* client-side <LogoGenerator>, which does all styling, live preview, and PNG
* export in the browser (no server data, no DB).
*/
export default function LogoPage() {
return (
<main style={{ display: "grid", gap: "1.5rem", maxWidth: 920, margin: "0 auto" }}>
<ContentCard
icon="🎨"
title="Logo generator"
subtitle="Design a logo for your hotel — pick a font, colours and size, then download it as a PNG."
/>
<LogoGenerator />
</main>
);
}