NoteStack-Test / frontend /src /components /StudyOverlay.tsx
HumeraR's picture
Refactor VideoTemplateEditor component: remove AI editing features and related state management, streamline template loading, and update styles for improved layout. Enhance CSS for responsive design and visual consistency across various components, including dropdowns, sync stats, and quiz elements. Remove deprecated premium badge styles and adjust layout for chat components.
66de9c8
Raw History Blame Contribute Delete
2.77 kB
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,
);
}