Skip to content
Merged
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
47 changes: 1 addition & 46 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,6 @@
--font-mono: var(--font-geist-mono);
}

/* The Media Pool door's red, for its one error. A light shade, for the
contrast text needs on dark grey. */
@theme {
--color-cp-red-text: #ff8a80;
}

/* Base document styles. Smooth scrolling only for visitors who have not asked
for less motion. An unconditional copy of this rule used to sit beside it,
which made the media query do nothing. */
Expand Down Expand Up @@ -1235,7 +1229,7 @@ section {

/* ── Media Pool door ───────────────────────────────────────────
/mediapool takes the suite's palette through .st-root and adds only
the record light and the button the suite has no equivalent for.
the record light the suite has no equivalent for.
─────────────────────────────────────────────────────────────── */

/* Grey: nothing is recording. */
Expand All @@ -1246,42 +1240,3 @@ section {
border-radius: 50%;
background: var(--st-faint);
}

.cp-btn {
display: inline-flex;
height: 28px;
flex-shrink: 0;
align-items: center;
justify-content: center;
gap: 6px;
border: 1px solid var(--st-line-strong);
border-radius: 3px;
background: var(--st-panel-hi);
padding: 0 10px;
font-size: 12px;
color: var(--st-dim);
white-space: nowrap;
transition: color 150ms ease, border-color 150ms ease, background-color 150ms ease;
}

.cp-btn:hover:not(:disabled) {
border-color: rgba(255, 255, 255, 0.3);
color: var(--st-text);
}

.cp-btn:disabled {
opacity: 0.45;
}

.cp-btn-primary {
border-color: transparent;
background: var(--st-accent);
color: #2a1a02;
font-weight: 500;
}

.cp-btn-primary:hover:not(:disabled) {
border-color: transparent;
color: #2a1a02;
filter: brightness(1.12);
}
78 changes: 47 additions & 31 deletions src/app/mediapool/Door.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use client";

import { useEffect, useState } from "react";
import { LuScanFace } from "react-icons/lu";
import { useEffect, useRef, useState } from "react";

/** Media Pool, Ali's fleet app, which answers only on his own tailnet. */
const MEDIA_POOL = "https://light-vm.tailde9e5d.ts.net:8088/";
Expand All @@ -23,15 +22,16 @@ async function reachable(signal: AbortSignal) {
* The way into Media Pool from this site: the viewer an editor shows for
* footage it cannot find, with the file's title bar across the top.
*
* Media Pool runs on Ali's own network and answers nothing outside it, so this
* page holds none of it. It asks whether this browser can reach Media Pool
* and, if it can, goes there, to a passkey page that looks the same as this
* one. Anyone else stays on the lock. A browser that reaches it is one of
* Ali's, so its visits stop counting on the site too.
* Media Pool's own sign-in is the only entrance, with the passkey, setup and
* "New device?" pairing. This page only finds out whether this browser can
* reach Media Pool and, if it can, goes there without a lock of its own. Anyone
* else stays on the lock. A browser that reaches it is one of Ali's, so its
* visits stop counting on the site too.
*/
export default function Door() {
const [phase, setPhase] = useState<"checking" | "opening" | "locked">("checking");
const [attempt, setAttempt] = useState(0);
const retry = useRef<HTMLButtonElement>(null);

useEffect(() => {
// Leaving the page, or trying again, drops this check, so a late answer can't redirect.
Expand All @@ -50,6 +50,13 @@ export default function Door() {
return () => check.abort();
}, [attempt]);

const locked = phase === "locked";

// A retry that fails again puts focus back on Try again, which went away while it checked.
useEffect(() => {
if (locked && attempt > 0) retry.current?.focus();
}, [locked, attempt]);

return (
<div className="st-root st-hatch flex min-h-[100dvh] flex-col bg-[var(--st-stage)] text-[var(--st-text)]">
<header className="flex shrink-0 items-center gap-2.5 border-b border-[var(--st-line)] bg-[var(--st-chrome)] px-3 py-2.5">
Expand All @@ -60,32 +67,41 @@ export default function Door() {

<main className="flex flex-1 items-center justify-center px-5 py-10">
<div className="w-full max-w-[380px]">
<p className="st-eyebrow">Media offline</p>
<h1 className="mt-3 text-[40px] font-semibold leading-[1.05] tracking-[-0.035em]">Locked</h1>
<button
type="button"
disabled={phase !== "locked"}
onClick={() => {
setPhase("checking");
setAttempt((n) => n + 1);
}}
className="cp-btn cp-btn-primary mt-6 h-11! w-full text-[14px]!"
>
<LuScanFace aria-hidden className="text-[18px]" />
{phase === "locked" ? "Unlock with passkey" : phase === "opening" ? "Opening…" : "Connecting…"}
</button>
<noscript>
<p className="mt-3 text-[12.5px] text-[var(--st-faint)]">Unlocking needs JavaScript.</p>
</noscript>
{phase === "locked" && attempt > 0 && (
<p role="alert" className="mt-3 text-[12.5px] text-cp-red-text">
Couldn&apos;t reach Media Pool from this page.{" "}
{/* A browser can block this page's check of a private address, but not a visit. */}
<a href={MEDIA_POOL} className="underline underline-offset-2">
Open it directly
</a>
<p className="st-eyebrow">{locked ? "Media offline" : "Media Pool"}</p>
{locked ? (
<>
<h1 className="mt-3 text-[40px] font-semibold leading-[1.05] tracking-[-0.035em]">Locked</h1>
<p role="alert" className="st-body mt-3 text-[13.5px]! leading-[1.6]! text-[var(--st-dim)]">
This page couldn&apos;t reach Media Pool.
</p>
<div className="mt-5 flex gap-4 text-[12.5px] text-[var(--st-faint)]">
<button
ref={retry}
type="button"
onClick={() => {
setPhase("checking");
setAttempt((n) => n + 1);
}}
className="underline-offset-4 transition-colors hover:text-[var(--st-text)] hover:underline"
>
Try again
</button>
{/* A browser can block this page's check of a private address, but not a visit. */}
<a href={MEDIA_POOL} className="underline-offset-4 transition-colors hover:text-[var(--st-text)] hover:underline">
Open it directly
</a>
</div>
</>
) : (
<p className="st-tc mt-3 text-[var(--st-faint)]" aria-live="polite">
Opening Media Pool…
</p>
)}
<noscript>
<p className="mt-3 text-[12.5px] text-[var(--st-faint)]">
Opening Media Pool needs JavaScript, or <a href={MEDIA_POOL} className="underline">open it directly</a>.
</p>
</noscript>
</div>
</main>
</div>
Expand Down
Loading