// ESTÚDIO — Páginas B: Kanban de produção, Banco de pautas. Persistidos via window.STORE. (function () { const { useState } = React; const D = window.DATA; const S = window.STORE; const { PlatRow, PerfilTag, Chip, EnergiaBadge, Stars, PageHead, Card, fmtData } = window.UI; const h = React.createElement; // ══════════════════ KANBAN ══════════════════ function Kanban() { const { state, actions } = S.useStore(); const [drag, setDrag] = useState(null); const [over, setOver] = useState(null); const [fPerfil, setFPerfil] = useState("todos"); const [detalhe, setDetalhe] = useState(null); const [novoId, setNovoId] = useState(null); const filtrados = state.conteudos.filter((c) => fPerfil === "todos" || c.perfis.includes(fPerfil)); const atual = detalhe ? state.conteudos.find((x) => x.id === detalhe) : null; function criar() { const id = actions.addConteudo({ perfis: fPerfil !== "todos" ? [fPerfil] : ["lore"] }); setNovoId(id); setDetalhe(id); } return h("div", { className: "page" }, h(PageHead, { titulo: "Produção", sub: "Arraste ou use “mover” · edite, duplique e gere legendas dentro do card", right: h("div", { style: { display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" } }, h("div", { className: "seg" }, [["todos", "Todos"], ...Object.values(D.perfis).map((p) => [p.id, p.nome])].map(([k, l]) => h("button", { key: k, className: "seg-btn" + (fPerfil === k ? " seg-on" : ""), onClick: () => setFPerfil(k) }, l))), h("button", { className: "btn-pink", onClick: criar }, "+ Novo conteúdo") ) }), h("div", { className: "kanban" }, D.etapas.map((et) => { const inCol = filtrados.filter((c) => c.status === et); return h("div", { key: et, className: "kb-col" + (over === et ? " kb-over" : ""), onDragOver: (e) => { e.preventDefault(); setOver(et); }, onDragLeave: () => setOver((o) => (o === et ? null : o)), onDrop: () => { if (drag) actions.moveConteudo(drag, et); setDrag(null); setOver(null); }, }, h("div", { className: "kb-col-head", style: { borderTopColor: (D.etapasMeta[et] || {}).cor } }, h("span", { className: "kb-col-name" }, h("span", { className: "kb-col-emoji" }, (D.etapasMeta[et] || {}).emoji), et), h("span", { className: "kb-count" }, inCol.length)), h("div", { className: "kb-col-body" }, inCol.map((c) => h(KbCard, { key: c.id, c, dragging: drag === c.id, onDragStart: () => setDrag(c.id), onDragEnd: () => { setDrag(null); setOver(null); }, onOpen: () => { setNovoId(null); setDetalhe(c.id); }, onMove: (st) => actions.moveConteudo(c.id, st), }))) ); })), atual && h(Modal, { c: atual, startEditing: detalhe === novoId, onClose: () => { setDetalhe(null); setNovoId(null); }, onSave: (patch) => actions.updateConteudo(detalhe, patch), onDelete: () => { actions.deleteConteudo(detalhe); setDetalhe(null); setNovoId(null); }, onDuplicate: () => { const nid = actions.duplicateConteudo(detalhe); setNovoId(null); setDetalhe(nid); }, onToggleChk: (i) => actions.toggleChecklist(detalhe, i), }) ); } // ── Card de produção ── function KbCard({ c, dragging, onDragStart, onDragEnd, onOpen, onMove }) { const pc = D.pilarCor[c.pilar] || { bg: "var(--white)", bd: "var(--gray-light)" }; return h("div", { className: "kb-card" + (dragging ? " kb-dragging" : ""), draggable: true, onDragStart, onDragEnd, style: { background: pc.bg, borderColor: pc.bd }, onClick: () => onOpen(), }, h("div", { className: "kb-title" }, c.titulo), h("div", { className: "kb-tags" }, h("span", { className: "kb-formato" }, c.formato), c.perfis.map((id) => h(PerfilTag, { key: id, id, dot: true })), c.collab && h("span", { className: "collab-flag" }, "⇄ collab"), h(PlatRow, { plats: c.plats, size: 15 }) ), c.publicacao && h("div", { className: "kb-pubdate" }, "📅 " + fmtData(c.publicacao)), h("div", { className: "kb-move", onClick: (e) => e.stopPropagation() }, h("span", { className: "kb-move-l" }, "Mover:"), h("select", { className: "pb-select", value: c.status, onChange: (e) => onMove(e.target.value) }, D.etapas.map((et) => h("option", { key: et, value: et }, et))) ) ); } const RESUMO = { p1: "Mostre o processo real e leve — bastidores de criar sem se esgotar. Gancho de dor (cansaço) + 1 método simples.", p2: "IA como copiloto prático: 1 fluxo ou prompt que economiza tempo. Sem jargão, mostre a tela.", p3: "Vulnerabilidade honesta de mãe + criadora. História pequena e específica gera identificação e salvamentos.", p4: "Compartilhe uma referência do seu repertório e como ela vira conteúdo. Bom para autoridade e SEO.", p5: "Ensine o método da Logue passo a passo. Prova de organização = confiança da marca.", p6: "Case com antes/depois + um número de contexto. Ótimo para atrair leads e parcerias.", p7: "Eduque a marca sobre o que trava a conversão. Lista/carrossel performa bem.", p8: "Conteúdo exclusivo, específico no tema. Diga o que o membro sai sabendo fazer + um recurso pra baixar.", }; function FullEditor({ c, onSave, onCancel }) { const [titulo, setTitulo] = useState(c.titulo); const [formato, setFormato] = useState(c.formato); const [perfis, setPerfis] = useState(c.perfis); const [plats, setPlats] = useState(c.plats); const [status, setStatus] = useState(c.status); const [gravacao, setGravacao] = useState(c.gravacao || ""); const [publicacao, setPublicacao] = useState(c.publicacao || ""); const [resumo, setResumo] = useState(c.resumo || RESUMO[c.pilar] || ""); const [conteudo, setConteudo] = useState(c.roteiro || ""); const [selPlats, setSelPlats] = useState(c.plats.slice(0, 1)); const [legenda, setLegenda] = useState(""); function tPerfil(id) { setPerfis((s) => s.includes(id) ? s.filter((x) => x !== id) : [...s, id]); } function tPlat(pl) { setPlats((s) => s.includes(pl) ? s.filter((x) => x !== pl) : [...s, pl]); } function tSel(pl) { setSelPlats((s) => s.includes(pl) ? s.filter((x) => x !== pl) : [...s, pl]); } function gerar() { const alvo = (selPlats.filter((x) => plats.includes(x))); const usar = alvo.length ? alvo : plats; const txt = usar.map((pl) => { const base = (c.legendas && c.legendas[pl]) || titulo; return "【 " + D.plataformas[pl].nome + " 】\n" + base + "\n\n👉 " + (pl === "linkedin" ? "Comenta sua opinião." : pl === "substack" ? "Assina a Carta da Lola." : "Salva e compartilha 💌"); }).join("\n\n"); setLegenda(txt); } return h("div", { className: "fed" }, h("div", { className: "kb-ed-label" }, "Título"), h("input", { className: "fed-input", value: titulo, onChange: (e) => setTitulo(e.target.value) }), h("div", { className: "fed-row" }, h("div", null, h("div", { className: "kb-ed-label" }, "Formato"), h("select", { className: "fed-select", value: formato, onChange: (e) => setFormato(e.target.value) }, D.formatos.map((f) => h("option", { key: f, value: f }, f))) ), h("div", null, h("div", { className: "kb-ed-label" }, "Etapa"), h("select", { className: "fed-select", value: status, onChange: (e) => setStatus(e.target.value) }, D.etapas.map((s) => h("option", { key: s, value: s }, s))) ) ), h("div", { className: "fed-row" }, h("div", null, h("div", { className: "kb-ed-label" }, "Gravação"), h("input", { type: "date", className: "fed-select", value: gravacao, onChange: (e) => setGravacao(e.target.value) })), h("div", null, h("div", { className: "kb-ed-label" }, "Publicação"), h("input", { type: "date", className: "fed-select", value: publicacao, onChange: (e) => setPublicacao(e.target.value) })) ), h("div", { className: "kb-ed-label" }, "Perfil"), h("div", { className: "kb-platsel" }, Object.values(D.perfis).map((pf) => h("button", { key: pf.id, className: "platsel" + (perfis.includes(pf.id) ? " on" : ""), onClick: () => tPerfil(pf.id) }, pf.nome))), h("div", { className: "kb-ed-label" }, "Plataformas"), h("div", { className: "kb-platsel" }, Object.entries(D.plataformas).map(([k, v]) => h("button", { key: k, className: "platsel" + (plats.includes(k) ? " on" : ""), onClick: () => tPlat(k) }, v.nome))), h("div", { className: "kb-ed-label" }, "💡 Ideia — o que pensei sobre esse tema"), h("textarea", { className: "kb-textarea", style: { minHeight: 54, background: "var(--pink-tint)" }, value: resumo, onChange: (e) => setResumo(e.target.value) }), h("div", { className: "kb-ed-label" }, "Conteúdo do post"), h("textarea", { className: "kb-textarea", value: conteudo, onChange: (e) => setConteudo(e.target.value), placeholder: "Escreve o roteiro / texto do post aqui…" }), plats.length > 1 && h("div", null, h("div", { className: "kb-ed-label" }, "Gerar legenda para:"), h("div", { className: "kb-platsel" }, plats.map((pl) => h("button", { key: pl, className: "platsel" + (selPlats.includes(pl) ? " on" : ""), onClick: () => tSel(pl) }, D.plataformas[pl].nome))) ), h("button", { className: "btn-pink sm", onClick: gerar }, "✨ Gerar legenda"), legenda && h("pre", { className: "kb-legenda" }, legenda), h("div", { className: "fed-actions" }, h("button", { className: "btn-ghost", onClick: onCancel }, "Cancelar"), h("button", { className: "btn-pink", onClick: () => onSave({ titulo, formato, perfis, plats, status, gravacao, publicacao, resumo, roteiro: conteudo }) }, "✓ Salvar") ) ); } function Modal({ c, startEditing, onClose, onSave, onDelete, onDuplicate, onToggleChk }) { const [editing, setEditing] = useState(!!startEditing); const [confirmDel, setConfirmDel] = useState(false); const p = D.pilares.find((x) => x.id === c.pilar); const reps = (c.repertorios || []).map((id) => D.repertorio.find((r) => r.id === id)).filter(Boolean); const roiMap = { autoridade: "Autoridade", venda: "Venda", compart: "Compartilhamento", seo: "SEO" }; return h("div", { className: "modal-bg", onClick: onClose }, h("div", { className: "modal", onClick: (e) => e.stopPropagation() }, h("button", { className: "modal-x", onClick: onClose }, "✕"), h("div", { className: "modal-tags" }, c.perfis.map((id) => h(PerfilTag, { key: id, id })), c.collab && h("span", { className: "collab-flag big" }, "⇄ collab")), editing ? h("div", null, h("div", { className: "msec-t", style: { fontSize: 15, marginBottom: 12 } }, "✏️ Editar conteúdo"), h(FullEditor, { c, onCancel: () => setEditing(false), onSave: (patch) => { onSave(patch); setEditing(false); } }) ) : h("div", null, h("div", { className: "modal-headrow" }, h("h2", { className: "modal-title" }, c.titulo), h("div", { style: { display: "flex", gap: 8, flexShrink: 0 } }, h("button", { className: "btn-ghost", onClick: onDuplicate, title: "Duplicar" }, "⎘ Duplicar"), h("button", { className: "btn-pink sm", onClick: () => setEditing(true) }, "✏️ Editar") ) ), h("div", { className: "modal-sub" }, c.formato, " · ", p && p.nome, " · ", h(PlatRow, { plats: c.plats, size: 18 })), c.resumo && h("div", { className: "modal-ideia" }, h("b", null, "💡 Ideia: "), c.resumo), c.roteiro && h("div", { className: "msec" }, h("div", { className: "msec-t" }, "Conteúdo do post"), h("p", { className: "modal-roteiro" }, c.roteiro)), h("div", { className: "modal-grid" }, h("div", { className: "mstat" }, h("span", null, "Objetivo"), h("b", null, c.objetivo)), h("div", { className: "mstat" }, h("span", null, "Energia"), h(EnergiaBadge, { e: c.energia })), h("div", { className: "mstat" }, h("span", null, "Tempo est."), h("b", null, c.tempo || "—")), h("div", { className: "mstat" }, h("span", null, "Gravação"), h("b", null, fmtData(c.gravacao))), h("div", { className: "mstat" }, h("span", null, "Publicação"), h("b", null, fmtData(c.publicacao))), h("div", { className: "mstat" }, h("span", null, "Etapa"), h("b", null, c.status)) ), c.roi && h("div", { className: "msec" }, h("div", { className: "msec-t" }, "ROI editorial"), h("div", { className: "roi-grid" }, Object.entries(c.roi).map(([k, v]) => h("div", { key: k, className: "roi-row" }, h("span", null, roiMap[k] || k), h(Stars, { n: v })))) ), Object.keys(c.legendas || {}).length > 0 && h("div", { className: "msec" }, h("div", { className: "msec-t" }, "Legendas por plataforma"), Object.entries(c.legendas).map(([k, v]) => h("div", { key: k, className: "leg-row" }, h(PlatRow, { plats: [k], size: 18 }), h("p", null, v))) ), (c.checklist || []).length > 0 && h("div", { className: "msec" }, h("div", { className: "msec-t" }, "Checklist pré-publicação"), c.checklist.map((it, i) => h("button", { key: i, className: "chk-row chk-btn", onClick: () => onToggleChk(i) }, h("span", { className: "chk-box" + (it.ok ? " chk-on" : "") }, it.ok ? "✓" : ""), it.t)) ), reps.length > 0 && h("div", { className: "msec" }, h("div", { className: "msec-t" }, "Repertório usado"), h("div", { className: "chip-wrap" }, reps.map((r) => h("span", { key: r.id, className: "mini-chip" }, r.titulo))) ), h("div", { className: "modal-danger" }, confirmDel ? h("div", { className: "del-confirm" }, h("span", null, "Apagar este conteúdo?"), h("button", { className: "btn-ghost", onClick: () => setConfirmDel(false) }, "Cancelar"), h("button", { className: "btn-del", onClick: onDelete }, "Sim, apagar") ) : h("button", { className: "btn-del-link", onClick: () => setConfirmDel(true) }, "🗑 Apagar conteúdo") ) ) ) ); } // ══════════════════ BANCO DE PAUTAS ══════════════════ const P_STATUS = ["ideia solta", "aprovada", "em produção", "descartada"]; const P_CORES = { "ideia solta": "#908F8E", aprovada: "#7FB68C", "em produção": "#E89B4C", descartada: "#C0BEBC" }; function Pautas() { const { state, actions } = S.useStore(); const [fPerfil, setFPerfil] = useState("todos"); const [fPlat, setFPlat] = useState("todas"); const [drag, setDrag] = useState(null); const [over, setOver] = useState(null); const [captura, setCaptura] = useState(""); const [capPerfil, setCapPerfil] = useState("lore"); const [showFiltros, setShowFiltros] = useState(false); const ativos = (fPerfil !== "todos" ? 1 : 0) + (fPlat !== "todas" ? 1 : 0); function capturar() { const t = captura.trim(); if (!t) return; actions.addPauta({ titulo: t, perfis: [capPerfil], status: "ideia solta" }); setCaptura(""); } const filtrados = state.pautas .filter((p) => fPerfil === "todos" || p.perfis.includes(fPerfil)) .filter((p) => fPlat === "todas" || p.plats.includes(fPlat)); function card(p) { const pil = D.pilares.find((x) => x.id === p.pilar); const pc = D.pilarCor[p.pilar] || { bg: "var(--white)", bd: "var(--gray-light)" }; return h("div", { key: p.id, className: "pb-card" + (drag === p.id ? " kb-dragging" : ""), draggable: true, onDragStart: () => setDrag(p.id), onDragEnd: () => { setDrag(null); setOver(null); }, style: { background: pc.bg, borderColor: pc.bd }, }, h("div", { className: "pb-top" }, p.perfis.map((id) => h(PerfilTag, { key: id, id, dot: true })), p.perfis.length > 1 && h("span", { className: "collab-flag" }, "⇄"), h("span", { className: "kb-formato" }, p.formato)), h("div", { className: "pb-title" }, p.titulo), pil && h("div", { className: "pb-pilar", style: { background: pc.bd + "66" } }, pil.nome), p.virou && h("div", { className: "pb-virou" }, "✓ virou conteúdo na produção"), h("div", { className: "pb-foot" }, h(PlatRow, { plats: p.plats, size: 16 }), h("select", { className: "pb-select", value: p.status, onChange: (e) => actions.setPautaStatus(p.id, e.target.value), onClick: (e) => e.stopPropagation() }, P_STATUS.map((s) => h("option", { key: s, value: s }, s))) ), !p.virou && h("button", { className: "pb-toprod", onClick: (e) => { e.stopPropagation(); actions.pautaToConteudo(p.id); } }, "→ Enviar pra produção") ); } return h("div", { className: "page" }, h(PageHead, { titulo: "Ideias & Pautas", sub: "Capture uma ideia, arraste entre as colunas ou envie a pauta direto pra produção" }), h("div", { className: "cap-bar" }, h("input", { className: "cap-bar-input", placeholder: "Joga a ideia aqui… (vira pauta em ‘ideia solta’)", value: captura, onChange: (e) => setCaptura(e.target.value), onKeyDown: (e) => { if (e.key === "Enter") capturar(); } }), h("div", { className: "seg" }, Object.values(D.perfis).map((p) => h("button", { key: p.id, className: "seg-btn" + (capPerfil === p.id ? " seg-on" : ""), onClick: () => setCapPerfil(p.id) }, p.nome))), h("button", { className: "btn-pink", onClick: capturar, disabled: !captura.trim() }, "+ Capturar") ), h("div", { className: "pautas-filterbar" }, h("button", { className: "filtrar-btn" + (showFiltros ? " on" : ""), onClick: () => setShowFiltros((s) => !s) }, "⚙ Filtrar", ativos > 0 && h("span", { className: "filtrar-count" }, ativos), h("span", { className: "filtrar-caret" }, showFiltros ? " ▲" : " ▼")), ativos > 0 && h("button", { className: "filtrar-clear", onClick: () => { setFPerfil("todos"); setFPlat("todas"); } }, "Limpar") ), showFiltros && h("div", { className: "cal-filters wrap pautas-filters" }, h("span", { className: "flabel" }, "Perfil:"), h(Chip, { active: fPerfil === "todos", onClick: () => setFPerfil("todos") }, "Todos"), Object.values(D.perfis).map((p) => h(Chip, { key: p.id, active: fPerfil === p.id, onClick: () => setFPerfil(p.id), color: p.cor }, p.nome)), h("span", { className: "flabel", style: { marginLeft: 12 } }, "Plataforma:"), h(Chip, { active: fPlat === "todas", onClick: () => setFPlat("todas") }, "Todas"), Object.entries(D.plataformas).map(([k, v]) => h(Chip, { key: k, active: fPlat === k, onClick: () => setFPlat(k), color: v.cor }, v.nome)) ), h("div", { className: "pilar-legend" }, D.pilares.map((pl) => { const pc = D.pilarCor[pl.id] || {}; return h("span", { key: pl.id, className: "pl-leg", style: { background: pc.bg, borderColor: pc.bd } }, h("span", { className: "pl-leg-dot", style: { background: pc.bd } }), pl.nome); })), h("div", { className: "pauta-board" }, P_STATUS.map((st) => { const inCol = filtrados.filter((p) => p.status === st); return h("div", { key: st, className: "pb-col" + (over === st ? " kb-over" : ""), onDragOver: (e) => { e.preventDefault(); setOver(st); }, onDragLeave: () => setOver((o) => (o === st ? null : o)), onDrop: () => { if (drag) actions.setPautaStatus(drag, st); setDrag(null); setOver(null); }, }, h("div", { className: "pb-col-head", style: { borderTopColor: P_CORES[st] } }, h("span", { className: "pb-col-name" }, st), h("span", { className: "kb-count" }, inCol.length)), h("div", { className: "pb-col-body" }, inCol.map(card)) ); })) ); } Object.assign(window, { Kanban, Pautas }); })();