anydrop/web/src/components/PublicRoomPanel.tsx
ordinarthur c18d995c3f feat(web): Paper & Envelope design system
Replace generic slate/indigo dark theme with a custom editorial
direction: warm paper neutrals, oxblood signal, Fraunces serif
display, Inter body, JetBrains Mono for codes. SVG paper-texture
noise overlay and thin rules across the app.

Refactored: Home, Settings, JoinRoom, Pair, Share, plus every
modal and panel (DropZone, DevicePairingPanel, PublicRoomPanel,
ProfileSetup, TextShareModal, ReceiveDialog, TransferProgress,
PeerList, PeerAvatar).

Also drops three pre-existing Uint8Array/BlobPart strictness
errors so the production build is green again.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 10:49:15 +02:00

122 lines
3.4 KiB
TypeScript

import { useState } from "react";
import { QRCodeSVG } from "qrcode.react";
import { useStore } from "../stores/useStore";
interface PublicRoomPanelProps {
onCreateRoom: () => void;
}
export default function PublicRoomPanel({ onCreateRoom }: PublicRoomPanelProps) {
const publicRoomCode = useStore((s) => s.publicRoomCode);
const publicRoomUrl = useStore((s) => s.publicRoomUrl);
const [showModal, setShowModal] = useState(false);
const handleClick = () => {
if (publicRoomCode && publicRoomUrl) {
setShowModal(true);
} else {
onCreateRoom();
setShowModal(true);
}
};
return (
<>
<button
onClick={handleClick}
className="paper-panel px-4 py-4 flex flex-col items-start gap-1
hover:border-ink transition-colors duration-fast ease-crisp
text-left"
>
<span className="font-mono text-[10px] uppercase tracking-[0.22em] text-ink-muted">
Public link
</span>
<span className="text-sm text-ink">Send to anyone </span>
</button>
{showModal && (
<PublicRoomModal
code={publicRoomCode}
url={publicRoomUrl}
onClose={() => setShowModal(false)}
/>
)}
</>
);
}
function PublicRoomModal({
code,
url,
onClose,
}: {
code: string | null;
url: string | null;
onClose: () => void;
}) {
const [copied, setCopied] = useState(false);
const copyToClipboard = () => {
if (!url) return;
navigator.clipboard.writeText(url);
setCopied(true);
setTimeout(() => setCopied(false), 1500);
};
return (
<div
className="fixed inset-0 z-50 bg-ink/40 flex items-center justify-center p-4"
onClick={onClose}
>
<div
className="paper-panel shadow-lift rounded-sm p-6 max-w-sm w-full"
onClick={(e) => e.stopPropagation()}
>
<div className="text-xs uppercase tracking-[0.2em] text-ink-muted">
Public link
</div>
<h3 className="font-display text-2xl text-ink mt-1 mb-5">
Receive from anyone
</h3>
{!code || !url ? (
<p className="text-sm text-ink-muted">Generating</p>
) : (
<>
<div className="flex justify-center mb-5">
<div className="bg-paper p-3 border border-paper-edge rounded-sm">
<QRCodeSVG value={url} size={180} bgColor="#F5F0E6" fgColor="#1A1714" />
</div>
</div>
<div className="text-center space-y-2">
<p className="font-mono text-3xl font-medium text-signal tracking-[0.3em]">
{code.toUpperCase()}
</p>
<button
onClick={copyToClipboard}
className="text-xs text-ink-muted hover:text-ink transition-colors
font-mono break-all"
>
{copied ? "Copied ✓" : url}
</button>
</div>
<p className="text-xs text-ink-muted mt-5 leading-relaxed">
Anyone with this code or link can send you files. Expires in 10 minutes.
</p>
</>
)}
<button
onClick={onClose}
className="mt-6 w-full py-2.5 border border-paper-edge hover:border-ink
text-sm text-ink rounded-sm transition-colors duration-fast ease-crisp"
>
Close
</button>
</div>
</div>
);
}