/* global React, window */ /* SHEET CREATOR — aba "Ficha" do grimório. Preview + exportação. */ (function () { "use strict"; const { useState, useEffect, useCallback } = React; function lsGet(k) { try { return JSON.parse(localStorage.getItem(k)); } catch { return null; } } function lsSet(k, v) { try { localStorage.setItem(k, JSON.stringify(v)); } catch {} } function FcCorners() { return ( <> > ); } function useCharName() { const [name, setName] = useState(() => lsGet("arton_char_name") || ""); useEffect(() => { const onChange = () => setName(lsGet("arton_char_name") || ""); window.addEventListener("arton:char-changed", onChange); window.addEventListener("storage", onChange); return () => { window.removeEventListener("arton:char-changed", onChange); window.removeEventListener("storage", onChange); }; }, []); const update = useCallback((v) => { setName(v); lsSet("arton_char_name", v); try { window.dispatchEvent(new CustomEvent("arton:char-changed")); } catch {} }, []); return [name, update]; } function buildSummary() { const cls = lsGet("arton_char_class") || { classes: [] }; const race = lsGet("arton_char_race"); const origin = lsGet("arton_char_origin"); const deity = lsGet("arton_char_deity"); const attrs = lsGet("arton_char_attrs"); const skills = lsGet("arton_skills") || {}; const classes = (cls.classes || []).filter(c => c.className); const totalLevel = classes.reduce((a, c) => a + (c.level || 0), 0); return { classes, race, origin, deity, attrs, totalLevel, classCount: classes.length, skillsChosen: (skills.choices || []).length + (skills.int_bonus_choices || []).length, hasAttrs: !!(attrs && (attrs.base_buy || attrs.base_roll)), }; } function useCharSummary() { const [s, setS] = useState(() => buildSummary()); useEffect(() => { const onChange = () => setS(buildSummary()); window.addEventListener("arton:char-changed", onChange); document.addEventListener("arton:char-changed", onChange); window.addEventListener("storage", onChange); return () => { window.removeEventListener("arton:char-changed", onChange); document.removeEventListener("arton:char-changed", onChange); window.removeEventListener("storage", onChange); }; }, []); return s; } function SheetCreator() { const [name, setName] = useCharName(); const summary = useCharSummary(); const [status, setStatus] = useState(null); const [busy, setBusy] = useState(false); const [importOpen, setImportOpen] = useState(false); const missing = []; if (!summary.classCount) missing.push("Classe"); if (!summary.hasAttrs) missing.push("Atributos"); if (!summary.race) missing.push("Raça"); if (!summary.origin) missing.push("Origem"); const canExport = !!name.trim(); const onExport = async () => { setBusy(true); setStatus(null); try { const res = await window.SHEET_EXPORT.downloadPdf(name); setStatus({ type: "ok", msg: `Baixado: ${res.filename}` }); } catch (e) { setStatus({ type: "err", msg: e.message || String(e) }); } finally { setBusy(false); } }; const onCopyCode = async () => { try { const payload = window.SHEET_EXPORT.buildPayload(name); const code = window.SHEET_EXPORT.encodeCode(payload); await navigator.clipboard.writeText(code); setStatus({ type: "ok", msg: "Código copiado para a área de transferência" }); } catch (e) { setStatus({ type: "err", msg: e.message || String(e) }); } }; return (
Confira o que entrará no PDF antes de exportar.
O PDF inclui um código no rodapé que permite reimportar este personagem para edição no Escriba. Você pode copiar agora ou após exportar.