Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 45 additions & 33 deletions app/c/[id]/clip-client.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,61 +30,73 @@ export default function ClipClient({
}, []);

return (
<main className="relative h-dvh w-dvw overflow-hidden bg-void">
<div className="scanlines absolute inset-0" onClick={() => !soundOn && setSound(true)}>
<video
ref={videoRef}
src={clip.videoUrl}
autoPlay
loop
muted
playsInline
className="h-full w-full object-contain"
/>
{!soundOn && (
<div className="pointer-events-none absolute bottom-28 left-1/2 -translate-x-1/2 rounded-sm border-2 border-mustard bg-black/75 px-4 py-2 text-xs font-bold tracking-[0.2em] text-mustard">
🔇 TAP FOR SOUND
</div>
)}
</div>

<main className="relative flex h-dvh w-dvw flex-col overflow-hidden bg-void md:block">
{/* ---- top bar ---- */}
<div className="absolute left-0 right-0 top-0 flex items-center justify-between p-4">
<div className="flex items-center gap-3">
<div className="relative z-10 flex shrink-0 items-center justify-between gap-2 px-3 py-2 md:absolute md:inset-x-0 md:top-0 md:p-4">
<div className="flex items-center gap-2 md:gap-3">
<Link
href="/"
className="font-[family-name:var(--font-display)] text-2xl leading-none text-mustard drop-shadow-[3px_3px_0_#e63946]"
className="font-[family-name:var(--font-display)] text-xl leading-none text-mustard drop-shadow-[3px_3px_0_#e63946] md:text-2xl"
>
INFINITE
</Link>
<span className="rounded-sm border-2 border-teal bg-black/60 px-2 py-0.5 text-xs font-bold tracking-widest text-teal">
<span className="whitespace-nowrap rounded-sm border-2 border-teal bg-black/60 px-2 py-0.5 text-xs font-bold tracking-widest text-teal">
REPLAY
</span>
</div>
<div className="flex items-center gap-3">
<div className="flex items-center gap-2 md:gap-3">
<ShareButton clipId={clip.id} title={clip.title} />
<button
onClick={() => setSound(!soundOn)}
className="rounded-sm border-2 border-cream/60 bg-black/60 px-3 py-1 text-xs font-bold tracking-widest hover:border-teal hover:text-teal"
aria-label={soundOn ? "Turn sound off" : "Turn sound on"}
className="whitespace-nowrap rounded-sm border-2 border-cream/60 bg-black/60 px-3 py-1 text-xs font-bold tracking-widest hover:border-teal hover:text-teal"
>
{soundOn ? "SOUND: ON" : "SOUND: OFF"}
<span className="md:hidden">{soundOn ? "🔊 ON" : "🔇 OFF"}</span>
<span className="hidden md:inline">
{soundOn ? "SOUND: ON" : "SOUND: OFF"}
</span>
</button>
</div>
</div>

{/* ---- player ---- */}
<div
className="scanlines relative aspect-video w-full shrink-0 md:absolute md:inset-0 md:aspect-auto"
onClick={() => !soundOn && setSound(true)}
>
<video
ref={videoRef}
src={clip.videoUrl}
autoPlay
loop
muted
playsInline
className="h-full w-full object-contain"
/>
{!soundOn && (
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
<div className="rounded-sm border-2 border-mustard bg-black/75 px-4 py-2 text-xs font-bold tracking-[0.2em] text-mustard">
🔇 TAP FOR SOUND
</div>
</div>
)}
</div>

{/* ---- lower third ---- */}
<div className="pointer-events-none absolute bottom-20 left-4 max-w-[80vw] border-l-4 border-orange bg-black/70 px-4 py-2 md:bottom-24">
<div className="text-[10px] uppercase tracking-[0.3em] text-teal">
From the archive
</div>
<div className="font-[family-name:var(--font-display)] text-lg text-cream">
{clip.title}
<div className="pointer-events-none min-h-0 flex-1 px-3 pt-3 md:absolute md:bottom-24 md:left-4 md:flex-none md:p-0">
<div className="w-fit max-w-full border-l-4 border-orange bg-black/70 px-4 py-2 md:max-w-[80vw]">
<div className="text-[10px] uppercase tracking-[0.3em] text-teal">
From the archive
</div>
<div className="font-[family-name:var(--font-display)] text-base text-cream md:text-lg">
{clip.title}
</div>
<div className="text-xs opacity-70">{credit}</div>
</div>
<div className="text-xs opacity-70">{credit}</div>
</div>

{/* ---- bottom bar ---- */}
<div className="absolute bottom-0 left-0 right-0 flex items-center gap-3 border-t-4 border-mustard bg-panel px-4 py-3">
<div className="flex shrink-0 items-center gap-3 border-t-4 border-mustard bg-panel px-3 pt-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] md:absolute md:inset-x-0 md:bottom-0 md:px-4">
<Link
href="/"
className="shrink-0 rounded-sm border-2 border-orange bg-orange px-4 py-2 font-[family-name:var(--font-display)] text-sm text-void hover:border-mustard hover:bg-mustard"
Expand Down
32 changes: 9 additions & 23 deletions app/chat-panel.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,15 +20,10 @@ export interface ChatAuthor {

export default function ChatPanel({
identity,
open,
onClose,
onFund,
fundDisabled,
}: {
identity: Identity;
/** Mobile: whether the overlay is showing. Desktop always shows it. */
open: boolean;
onClose: () => void;
onFund: (text: string, author: ChatAuthor) => void;
fundDisabled: boolean;
}) {
Expand DownExpand Up@@ -68,7 +63,7 @@ export default function ChatPanel({
useEffect(() => {
const el = list.current;
if (el && stickToBottom.current) el.scrollTop = el.scrollHeight;
}, [messages, open]);
}, [messages]);

const onScroll = useCallback(() => {
const el = list.current;
Expand DownExpand Up@@ -112,7 +107,7 @@ export default function ChatPanel({

return (
<aside
className={`${open ? "flex" : "hidden"} absolute inset-0 z-[5] w-full flex-col bg-panel md:static md:z-auto md:flex md:w-80 md:shrink-0 md:border-l-4 md:border-mustard`}
className="flex min-h-0 min-w-0 flex-1 flex-col border-t-4 border-mustard bg-panel md:w-80 md:flex-none md:border-t-0 md:border-l-4"
aria-label="Live chat"
>
<div className="flex items-center justify-between border-b-2 border-cream/20 px-3 py-2">
Expand All@@ -127,24 +122,15 @@ export default function ChatPanel({
{relays > 0 ? "● NOSTR" : "○ CONNECTING"}
</span>
</div>
<div className="flex items-center gap-2">
{muted.size > 0 && (
<button
onClick={unmuteAll}
className="text-[10px] tracking-wider text-cream/50 hover:text-teal"
title="Clear your mute list"
>
{muted.size} MUTED
</button>
)}
{muted.size > 0 && (
<button
onClick={onClose}
aria-label="Close chat"
className="border-2 border-cream/40 px-2 text-sm hover:border-danger hover:text-danger md:hidden"
onClick={unmuteAll}
className="text-[10px] tracking-wider text-cream/50 hover:text-teal"
title="Clear your mute list"
>
{muted.size} MUTED
</button>
</div>
)}
</div>

<div ref={list} onScroll={onScroll} className="min-h-0 flex-1 overflow-y-auto py-1">
Expand DownExpand Up@@ -207,7 +193,7 @@ export default function ChatPanel({
maxLength={CHAT_MAX_LEN}
placeholder={`Yell at the TV as ${identity.name}…`}
aria-label="Chat message"
className="min-w-0 flex-1 border-2 border-teal/60 bg-void px-2 py-1.5 text-sm outline-none focus:border-teal"
className="min-w-0 flex-1 border-2 border-teal/60 bg-void px-2 py-1.5 text-base outline-none focus:border-teal md:text-sm"
/>
<button
type="submit"
Expand Down
11 changes: 10 additions & 1 deletion app/layout.tsx
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
import type { Metadata } from "next";
import type { Metadata, Viewport } from "next";
import { Bungee, Space_Grotesk } from "next/font/google";
import "./globals.css";

Expand DownExpand Up@@ -36,6 +36,15 @@ export const metadata: Metadata = {
},
};

// viewport-fit=cover lets the bottom bar pad itself past the iPhone home
// indicator (see pb-[env(safe-area-inset-bottom)] on the bars).
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
viewportFit: "cover",
themeColor: "#0d0b0e",
};

export default function RootLayout({
children,
}: Readonly<{
Expand Down
Loading