Spaces:
Runtime error
Runtime error
File size: 2,773 Bytes
0649f1b 66de9c8 0649f1b 66de9c8 0649f1b 66de9c8 0649f1b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | import { useEffect, useState, type ReactNode } from "react";
import { createPortal } from "react-dom";
/** A popup (a quiz, a flashcard deck) in the same dialog as the other creators, which can be
* minimised to a small pill in the corner and brought back, keeping its place. Escape minimises. */
export function StudyOverlay({ title, onClose, children }: { title: string; onClose: () => void; children: ReactNode }) {
const [minimized, setMinimized] = useState(false);
useEffect(() => {
if (minimized) return;
const onKey = (e: KeyboardEvent) => e.key === "Escape" && setMinimized(true);
document.addEventListener("keydown", onKey);
return () => document.removeEventListener("keydown", onKey);
}, [minimized]);
return createPortal(
<>
{/* Stays mounted while minimised, so the answers given so far are kept */}
<div className="modal-backdrop so-backdrop" hidden={minimized} onMouseDown={(e) => e.target === e.currentTarget && setMinimized(true)}>
<div className="modal card modal-wide so-modal" role="dialog" aria-modal="true" aria-label={title}>
<div className="modal-head">
<h2 className="so-title">{title}</h2>
<div className="so-actions">
<button type="button" className="icon-btn" onClick={() => setMinimized(true)} aria-label="Minimise" title="Minimise">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round">
<path d="M5 19h14" />
</svg>
</button>
<button type="button" className="icon-btn" onClick={onClose} aria-label="Close" title="Close">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6">
<path d="M6 6l12 12M18 6L6 18" />
</svg>
</button>
</div>
</div>
<div className="so-content">{children}</div>
</div>
</div>
{minimized && (
<div className="so-pill">
<button type="button" className="so-pill-open" onClick={() => setMinimized(false)} title="Open again">
<span className="so-pill-dot" aria-hidden="true" />
<span className="so-pill-title">{title}</span>
<span className="link-btn">Open</span>
</button>
<button type="button" className="icon-btn so-pill-close" onClick={onClose} aria-label="Close" title="Close">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
<path d="M6 6l12 12M18 6L6 18" />
</svg>
</button>
</div>
)}
</>,
document.body,
);
}
|