/* global React, Card, Button, Input, Ic, VS, LoadingState, ErrorState */
// ============================================================
// SCHEMA PICKER — full-screen modal with grid of thumbnails
// ============================================================
function SchemaPicker({ currentId, onPick, onClose }) {
const [list, setList] = React.useState(null);
const [cats, setCats] = React.useState(null);
const [err, setErr] = React.useState('');
const [q, setQ] = React.useState('');
const [cat, setCat] = React.useState(''); // '' = all
React.useEffect(() => {
VS.schemaLibrary()
.then((r) => setList(r || []))
.catch((e) => setErr(e.message));
VS.schemaLibraryCategories()
.then((r) => setCats(r || []))
.catch(() => setCats([]));
}, []);
// ESC → close
React.useEffect(() => {
function onKey(e) { if (e.key === 'Escape') onClose && onClose(); }
document.addEventListener('keydown', onKey);
return () => document.removeEventListener('keydown', onKey);
}, [onClose]);
const filtered = React.useMemo(() => {
if (!list) return [];
const qq = (q || '').trim().toLowerCase();
return list.filter((it) => {
if (cat && (it.category || '') !== cat) return false;
if (!qq) return true;
return (
(it.name || '').toLowerCase().includes(qq) ||
(it.category || '').toLowerCase().includes(qq) ||
(it.filename || '').toLowerCase().includes(qq)
);
});
}, [list, q, cat]);
function pick(item) {
if (onPick) onPick(item.id, item.name);
if (onClose) onClose();
}
return (
e.stopPropagation()}
style={{
width: 'min(1100px, 100%)',
maxHeight: 'calc(100vh - 48px)',
background: 'var(--bg)',
border: '1px solid var(--border)',
borderRadius: 'var(--r-md)',
boxShadow: '0 20px 60px rgba(0,0,0,0.35)',
display: 'flex', flexDirection: 'column',
overflow: 'hidden',
}}
>
{/* Header */}
Biblioteka schematów
Wybierz schemat z biblioteki
{/* Toolbar: search + categories */}
}
placeholder="Szukaj po nazwie lub kategorii…"
value={q}
onChange={(e) => setQ(e.target.value)}
/>
{/* Category chips */}
setCat('')}
label="Wszystkie"
count={list ? list.length : undefined}
/>
{(cats || []).map((c) => (
setCat(c.category)}
label={c.category || '— bez kategorii —'}
count={c.count}
/>
))}
{/* Grid */}
{err &&
}
{!err && !list &&
}
{!err && list && list.length === 0 && (
Biblioteka pusta
Administrator może dodać schematy w Konfiguracji.
)}
{!err && list && list.length > 0 && filtered.length === 0 && (
Brak wyników dla wybranych filtrów.
)}
{!err && filtered.length > 0 && (
{filtered.map((it) => (
pick(it)}
/>
))}
)}
{/* Footer */}
{list ? `${filtered.length} / ${list.length} schematów` : ''}
);
}
function CategoryChip({ active, onClick, label, count }) {
return (
);
}
function SchemaTile({ item, selected, onClick }) {
const [hover, setHover] = React.useState(false);
return (
setHover(true)}
onMouseLeave={() => setHover(false)}
style={{
display: 'flex', flexDirection: 'column',
background: 'var(--surface)',
border: '1px solid ' + (selected ? 'var(--accent)' : hover ? 'var(--border-strong)' : 'var(--border)'),
boxShadow: selected ? '0 0 0 2px var(--accent-weak)' : 'none',
borderRadius: 'var(--r-sm)',
overflow: 'hidden',
cursor: 'pointer',
transition: 'border-color 0.12s, box-shadow 0.12s',
}}
>
})
{ e.currentTarget.style.visibility = 'hidden'; }}
/>
{item.name || item.filename || '—'}
{item.category && (
{item.category}
)}
);
}
Object.assign(window, { SchemaPicker });