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:
1 parent
80f591a343
commit
8cedf5614e
4 files changed
+426
No files matched your search
@@ -4,6 +4,7 @@ import { getLocale, getMessages } from "next-intl/server";
|
|||||||
import { Nunito } from "next/font/google";
|
import { Nunito } from "next/font/google";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { Navigation } from "@/components/navigation";
|
import { Navigation } from "@/components/navigation";
|
||||||
|
import RadioPlayerGate from "@/components/public/radio-player-gate";
|
||||||
import { SiteFooter } from "@/components/site-footer";
|
import { SiteFooter } from "@/components/site-footer";
|
||||||
import { SiteHeader } from "@/components/site-header";
|
import { SiteHeader } from "@/components/site-header";
|
||||||
import { ThemeVars } from "@/components/theme-vars";
|
import { ThemeVars } from "@/components/theme-vars";
|
||||||
@@ -57,6 +58,7 @@ export default async function RootLayout({ children }: { children: ReactNode })
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<SiteFooter />
|
<SiteFooter />
|
||||||
|
<RadioPlayerGate />
|
||||||
</NextIntlClientProvider>
|
</NextIntlClientProvider>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user