/* --- Icons.jsx --- */ (() => { /* Tecto UI Kit — icon set (Lucide-style, 1.75 stroke). Exposed on window.TectoIcons */ const React = window.React; function Ico({ size = 18, children, ...rest }) { return ( ); } const Play = (p) => ; const Download = (p) => ; const Save = (p) => ; const Sun = (p) => ; const Moon = (p) => ; const FileText = (p) => ; const Folder = (p) => ; const Clock = (p) => ; const Settings = (p) => ; const Search = (p) => ; const PanelLeft = (p) => ; const Columns = (p) => ; const Plus = (p) => ; const Check = (p) => ; const X = (p) => ; const Alert = (p) => ; const Lock = (p) => ; const Zap = (p) => ; const Menu = (p) => ; const More = (p) => ; const Copy = (p) => ; const Trash = (p) => ; const Chevron = (p) => ; const ZoomIn = (p) => ; const Maximize = (p) => ; const GitHub = (p) => ; const Layout = (p) => ; const Image = (p) => ; const Building = (p) => ; const Calendar = (p) => ; const Hash = (p) => ; const Type = (p) => ; const Sparkle = (p) => ; const Stamp = (p) => ; window.TectoIcons = { Play, Download, Save, Sun, Moon, FileText, Folder, Clock, Settings, Search, PanelLeft, Columns, Plus, Check, X, Alert, Lock, Zap, Menu, More, Copy, Trash, Chevron, ZoomIn, Maximize, GitHub, Layout, Image, Building, Calendar, Hash, Type, Sparkle, Stamp }; })(); /* --- Chrome.jsx --- */ (() => { /* Tecto UI Kit — logo lockup + app chrome (TopBar, LeftRail, StatusBar). window.TectoChrome */ const React = window.React; (function injectChromeCSS() { if (document.getElementById('tecto-kit-chrome-css')) return; const css = ` .tk-logo { display: inline-flex; align-items: center; gap: 9px; } .tk-logo__mark { width: 26px; height: 26px; border-radius: 7px; flex: none; } .tk-logo__word { font-family: var(--font-serif); font-size: 19px; font-weight: 600; letter-spacing: -0.02em; color: var(--ink-strong); } .tk-topbar { display: flex; align-items: center; gap: 10px; height: var(--topbar-h); padding: 0 12px; flex: none; background: var(--surface); border-bottom: 1px solid var(--border); } .tk-crumb { display: flex; align-items: center; gap: 7px; font-family: var(--font-sans); font-size: var(--text-sm); color: var(--ink-muted); } .tk-crumb b { color: var(--ink-strong); font-weight: 600; font-family: var(--font-mono); font-size: var(--text-sm); } .tk-topbar__spacer { flex: 1; } .tk-topbar__grp { display: flex; align-items: center; gap: 8px; } .tk-avatar { width: 28px; height: 28px; border-radius: 50%; background: var(--accent); color: var(--accent-on); display: inline-flex; align-items: center; justify-content: center; font-family: var(--font-sans); font-size: 12px; font-weight: 600; flex: none; } .tk-rail { width: var(--rail-w); flex: none; background: var(--surface-sunken); border-right: 1px solid var(--border); display: flex; flex-direction: column; align-items: center; padding: 10px 0; gap: 4px; } .tk-rail__btn { width: 38px; height: 38px; border-radius: var(--radius-md); border: none; background: transparent; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; color: var(--ink-muted); transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out); position: relative; } .tk-rail__btn:hover { background: var(--surface-hover); color: var(--ink); } .tk-rail__btn--active { background: var(--accent-subtle-bg); color: var(--accent-subtle-fg); } .tk-rail__btn--active::before { content: ""; position: absolute; left: -10px; top: 9px; bottom: 9px; width: 3px; border-radius: 3px; background: var(--accent); } .tk-rail__sp { flex: 1; } .tk-status { display: flex; align-items: center; gap: 14px; height: var(--statusbar-h); padding: 0 14px; flex: none; background: var(--surface-sunken); border-top: 1px solid var(--border); font-family: var(--font-mono); font-size: 11px; color: var(--ink-muted); } .tk-status__sp { flex: 1; } .tk-status b { color: var(--ink); font-weight: 500; } `; const el = document.createElement('style'); el.id = 'tecto-kit-chrome-css'; el.textContent = css; document.head.appendChild(el); })(); function Logo({ word = true }) { return ( {word && Tecto} ); } function TopBar({ crumb, theme, onToggleTheme }) { const I = window.TectoIcons; const { IconButton, Tooltip } = window.TectoDS; return (
{(crumb || []).map((c, i) => ( {i > 0 && } {i === crumb.length - 1 ? {c} : {c}} ))}
} /> : } onClick={onToggleTheme} /> T
); } function LeftRail({ view, setView, onLogout }) { const I = window.TectoIcons; const { Tooltip } = window.TectoDS; const items = [ { id: 'docs', label: 'Documentos', icon: I.Folder }, { id: 'templates', label: 'Plantillas', icon: I.Layout }, { id: 'assets', label: 'Assets', icon: I.Image }, { id: 'docview', label: 'Documentación', icon: I.FileText }, { id: 'editor', label: 'Editor de plantilla', icon: I.PanelLeft }, ]; return (
{items.map((it) => ( ))}
); } function StatusBar({ engine }) { return (
Tectonic 0.15 {engine} UTF-8 LaTeX
Ln 23, Col 4 112 palabras main.tex · guardado
); } window.TectoChrome = { Logo, TopBar, LeftRail, StatusBar }; })(); /* --- CorpDocs.jsx --- */ (() => { /* Tecto UI Kit — corporate document renders (the PDF output). window.TectoCorp */ const React = window.React; const DEFAULT_BRAND = { name: 'Acme Estudio', initials: 'A', color: '#1f3a5f', tint: '#eef2f7', rfc: 'ACM850101AA1', address: 'Av. Reforma 222, CDMX · acme.studio', }; const DEFAULT_DATA = { numero: '0123', fecha: '7 jun 2026', validez: '22 jun 2026', cliente: 'Globex Corporation', clienteRfc: 'GLO910215QX3', moneda: 'USD', iva: true, items: [ { desc: 'Diseño e implementación de API REST', qty: 1, price: 3200 }, { desc: 'Integración con pasarela de pago', qty: 1, price: 1400 }, { desc: 'Soporte y mantenimiento (mensual)', qty: 3, price: 400 }, ], notas: 'Validez de la oferta: 15 días. Precios en USD, no incluyen retenciones. 50% anticipo, 50% contra entrega.', }; function fmtMoney(n, moneda) { const s = n.toLocaleString('es-MX', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); return `$${s} ${moneda}`; } function totals(data) { const subtotal = data.items.reduce((a, it) => a + it.qty * it.price, 0); const iva = data.iva ? subtotal * 0.16 : 0; return { subtotal, iva, total: subtotal + iva }; } function CotizacionDoc({ data = DEFAULT_DATA, brand = DEFAULT_BRAND }) { const t = totals(data); const ink = '#1a2430'; const muted = '#5d6b7a'; return (
{/* Header */}
{brand.initials}
{brand.name}
{brand.address}
COTIZACIÓN
N.º {data.numero}
{/* Meta */}
Para
{data.cliente}
RFC {data.clienteRfc}
{[['Fecha', data.fecha], ['Válida hasta', data.validez], ['Moneda', data.moneda]].map(([k, v]) => (
{k}{v}
))}
{/* Items */}
DescripciónCantP. UnitImporte
{data.items.map((it, i) => (
{it.desc} {it.qty} {it.price.toLocaleString('es-MX', { minimumFractionDigits: 2 })} {(it.qty * it.price).toLocaleString('es-MX', { minimumFractionDigits: 2 })}
))} {/* Totals */}
{data.iva && }
Total {fmtMoney(t.total, data.moneda)}
{/* Notes */}
Condiciones
{data.notas}
{/* Footer */}
{brand.name} · RFC {brand.rfc}
{brand.address}
Firma autorizada
1 / 1
); } function Row({ k, v, muted }) { return (
{k} {v}
); } window.TectoCorp = { CotizacionDoc, fmtMoney, totals, DEFAULT_BRAND, DEFAULT_DATA }; })(); /* --- WorkspaceScreens.jsx --- */ (() => { /* Tecto UI Kit — document-workspace screens: Documentos, Plantillas, Assets. window.TectoWorkspace */ const React = window.React; (function injectWsCSS() { if (document.getElementById('tecto-kit-ws-css')) return; const css = ` .tk-ws { flex: 1; min-height: 0; overflow: auto; background: var(--bg); } .tk-ws__in { max-width: 960px; margin: 0 auto; padding: 30px 36px 70px; } .tk-ws__head { display: flex; align-items: flex-end; gap: 14px; margin-bottom: 6px; } .tk-ws__title { font-family: var(--font-serif); font-size: 28px; font-weight: 600; letter-spacing: -0.02em; color: var(--ink-strong); margin: 0; } .tk-ws__sub { font-family: var(--font-sans); font-size: var(--text-sm); color: var(--ink-muted); margin: 3px 0 0; } .tk-ws__sp { flex: 1; } .tk-ws__sec { font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-subtle); margin: 28px 0 13px; } .tk-quick { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; } .tk-quick__c { display: flex; align-items: center; gap: 11px; padding: 13px 14px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); cursor: pointer; transition: border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out); } .tk-quick__c:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); transform: translateY(-1px); } .tk-quick__ic { width: 34px; height: 34px; border-radius: 8px; flex: none; display: flex; align-items: center; justify-content: center; color: #fff; } .tk-quick__t b { display: block; font-family: var(--font-sans); font-size: var(--text-sm); font-weight: 600; color: var(--ink-strong); } .tk-quick__t span { font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-muted); } .tk-rows { display: flex; flex-direction: column; gap: 3px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 6px; box-shadow: var(--shadow-sm); } .tk-tpls { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; } .tk-tplc { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); overflow: hidden; cursor: pointer; transition: border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out); } .tk-tplc:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); transform: translateY(-2px); } .tk-tplc__thumb { height: 132px; background: var(--bg-subtle); padding: 16px 16px 0; display: flex; justify-content: center; } .tk-tplc__page { width: 100%; background: #fff; border-radius: 4px 4px 0 0; box-shadow: var(--shadow-md); padding: 11px; } .tk-tplc__band { height: 8px; border-radius: 2px; width: 46%; } .tk-tplc__ln { height: 3px; border-radius: 2px; background: #e4e7eb; margin-top: 6px; } .tk-tplc__chip { height: 11px; width: 38%; border-radius: 2px; margin: 9px 0 0 auto; } .tk-tplc__foot { display: flex; align-items: center; gap: 8px; padding: 11px 13px; } .tk-tplc__foot b { font-family: var(--font-sans); font-size: var(--text-sm); font-weight: 600; color: var(--ink-strong); } .tk-tplc__foot span { font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-muted); margin-left: auto; } .tk-tplc--new { border-style: dashed; box-shadow: none; display: flex; align-items: center; justify-content: center; min-height: 188px; } .tk-tplc--new:hover { border-color: var(--accent); background: var(--accent-subtle-bg); } .tk-tplc__new { display: flex; flex-direction: column; align-items: center; gap: 4px; color: var(--ink-muted); } .tk-tplc__new span { font-family: var(--font-sans); font-size: var(--text-sm); font-weight: 600; color: var(--ink); margin-top: 4px; } .tk-tplc__new em { font-family: var(--font-mono); font-size: 10px; font-style: normal; color: var(--ink-subtle); } .tk-assets { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; } .tk-asset { display: flex; flex-direction: column; gap: 9px; padding: 13px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); } .tk-asset__box { height: 76px; border-radius: var(--radius-sm); border: 1px dashed var(--border-strong); display: flex; align-items: center; justify-content: center; background: var(--surface-sunken); } .tk-asset__n { font-family: var(--font-mono); font-size: 11px; color: var(--ink); } .tk-asset__m { font-family: var(--font-sans); font-size: 10.5px; color: var(--ink-subtle); } .tk-fonts { display: flex; flex-direction: column; gap: 3px; } `; const el = document.createElement('style'); el.id = 'tecto-kit-ws-css'; el.textContent = css; document.head.appendChild(el); })(); const TEMPLATES = [ { name: 'Cotización', cls: 'cotizacion.cls', color: '#1f3a5f', icon: 'FileText' }, { name: 'Factura', cls: 'factura.cls', color: '#1f6b4f', icon: 'Hash' }, { name: 'Contrato', cls: 'contrato.cls', color: '#5b4636', icon: 'Stamp' }, { name: 'Propuesta', cls: 'propuesta.cls', color: '#6d3a8f', icon: 'Sparkle' }, { name: 'SRS', cls: 'srs.cls', color: '#2a5f8f', icon: 'Layout' }, { name: 'Informe', cls: 'informe.cls', color: '#8a5a12', icon: 'FileText' }, ]; function Documentos({ onNew, onOpenDoc }) { const I = window.TectoIcons; const { Button, StatusPill, DocRow, Badge } = window.TectoDS; return (

Documentos

Elige una plantilla, llena los datos, descarga el PDF. Sin tocar LaTeX.

Crear nuevo
{TEMPLATES.map((t) => { const Icon = I[t.icon] || I.FileText; return (
onNew(t.name)}>
{t.name}{t.cls}
); })}
Recientes
onOpenDoc('Cotización')} aside={} /> onOpenDoc('Cotización')} aside={} /> onOpenDoc('Cotización')} aside={} /> onOpenDoc('Cotización')} aside={} />
); } function Plantillas({ onNew, onEdit }) { const I = window.TectoIcons; const { Button, Badge, IconButton } = window.TectoDS; return (

Plantillas

Tú las creas: una carpeta con su .cls, sus campos y sus assets (propios o globales). El Generador las usa con datos.

Tus plantillas
onEdit('nueva')}>
Nueva plantillacarpeta + .cls + assets
{TEMPLATES.map((t) => (
onNew(t.name)}>
{t.name}{t.cls} } onClick={(e) => { e.stopPropagation(); onEdit(t.name); }} />
))}
); } function Assets() { const I = window.TectoIcons; const { Badge } = window.TectoDS; return (

Assets

Logos, fuentes e imágenes que comparten todas tus plantillas.

Logos
{[['acme-logo.svg', 'SVG · 1:1'], ['acme-horizontal.svg', 'SVG · 4:1'], ['acme-mono.svg', 'SVG · mono'], ['favicon.png', 'PNG · 64px']].map(([n, m]) => (
A
{n}
{m}
))}
Fuentes
{[['IBM Plex Serif', 'titulares'], ['IBM Plex Sans', 'cuerpo'], ['IBM Plex Mono', 'datos'], ['Söhne', 'marca · opcional']].map(([n, m]) => (
Aa
{n}
{m}
))}
Imágenes
{[['portada.jpg', '1920×1080'], ['sello.png', 'PNG · α'], ['firma.png', 'PNG · α'], ['marca-agua.svg', 'SVG']].map(([n, m]) => (
{n}
{m}
))}
); } window.TectoWorkspace = { Documentos, Plantillas, Assets }; })(); /* --- Generator.jsx --- */ (() => { /* Tecto UI Kit — document Generator: form (left) → live corporate PDF (right). window.TectoGenerator */ const React = window.React; (function injectGenCSS() { if (document.getElementById('tecto-kit-gen-css')) return; const css = ` .tk-gen { flex: 1; min-height: 0; display: flex; } .tk-gen__form { width: 432px; flex: none; min-height: 0; overflow: auto; background: var(--surface); border-right: 1px solid var(--border); } .tk-gen__form-in { padding: 20px 22px 60px; display: flex; flex-direction: column; gap: 16px; } .tk-gen__head { display: flex; align-items: center; gap: 10px; } .tk-gen__head h2 { font-family: var(--font-serif); font-size: 20px; font-weight: 600; letter-spacing: -0.01em; color: var(--ink-strong); margin: 0; } .tk-gen__sec { font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-subtle); margin: 6px 0 -4px; } .tk-gen__grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } .tk-gen__item { display: grid; grid-template-columns: 1fr 52px 84px 28px; gap: 7px; align-items: center; } .tk-gen__item-h { display: grid; grid-template-columns: 1fr 52px 84px 28px; gap: 7px; font-family: var(--font-mono); font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-subtle); padding: 0 2px; } .tk-gen__totals { display: flex; flex-direction: column; gap: 4px; padding: 12px 14px; background: var(--surface-sunken); border: 1px solid var(--border); border-radius: var(--radius-md); font-family: var(--font-mono); font-size: 12px; } .tk-gen__totals .r { display: flex; justify-content: space-between; } .tk-gen__totals .t { font-weight: 600; color: var(--ink-strong); font-size: 14px; padding-top: 6px; margin-top: 2px; border-top: 1px solid var(--border-strong); } .tk-gen__preview { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; background: var(--bg-subtle); } .tk-gen__bar { display: flex; align-items: center; gap: 8px; height: 44px; padding: 0 14px; flex: none; background: var(--surface); border-bottom: 1px solid var(--border); } .tk-gen__bar b { font-family: var(--font-mono); font-size: 12px; color: var(--ink-muted); } .tk-gen__sp { flex: 1; } .tk-gen__stage { flex: 1; min-height: 0; overflow: auto; padding: 28px; display: flex; justify-content: center; align-items: flex-start; position: relative; } .tk-gen__page { width: 480px; background: var(--paper); box-shadow: var(--shadow-lg); border-radius: 2px; } .tk-gen__overlay { position: absolute; inset: 0; display: flex; flex-direction: column; gap: 13px; align-items: center; justify-content: center; background: color-mix(in srgb, var(--bg-subtle) 78%, transparent); backdrop-filter: blur(1.5px); } .tk-gen__overlay span { font-family: var(--font-mono); font-size: 13px; color: var(--ink-muted); } `; const el = document.createElement('style'); el.id = 'tecto-kit-gen-css'; el.textContent = css; document.head.appendChild(el); })(); function Generator({ data, setData, status, onCompile, onDownload, pdfUrl }) { const I = window.TectoIcons; const { Input, Select, Switch, Textarea, Button, IconButton, Badge, StatusPill } = window.TectoDS; const TA = Textarea || ((p) =>