- theme.css reescrito: paleta light (sky/emerald accents, slate neutrals), tokens de spacing/typography/radii/shadows, @font-face Inter + JetBrains Mono variable woff2 self-hosted. - ops-shell: header blanco con nav active=accent-soft + status pill pastel. - run-timeline: bubbles emerald-100 (user) / blue-100 (bot) sobre blanco. - home-dashboard: helpers cssVar + withAlpha, 6 charts coordinados a paleta pastel (--chart-blue/green/purple/orange/pink/gray). - 8 CRUDs (users, products, orders, conversations, aliases, recommendations, quantities, takeovers, settings, debug) migrados de hex hardcoded oscuros a var(--*). - modal.js + toast.js refactor a vars con fallbacks; modal blanco con shadow-lg y soft icon backgrounds. - test-panel: aliases :host apuntan a globals en vez de override dark. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
96 lines
2.9 KiB
JavaScript
96 lines
2.9 KiB
JavaScript
/**
|
|
* Toast service global. Sin dependencias.
|
|
* Inyecta un container en <body> y empuja toasts apilados.
|
|
*
|
|
* Uso:
|
|
* import { toast } from "./toast.js";
|
|
* toast({ kind: "error", text: "No se pudo guardar" });
|
|
* toast({ kind: "ok", text: "Listo", ms: 2000 });
|
|
*/
|
|
|
|
// Lee var del :root con fallback. Permite que la paleta de toasts se adapte
|
|
// al tema sin que el archivo conozca los hex.
|
|
function v(name, fallback) {
|
|
try {
|
|
const c = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
return c || fallback;
|
|
} catch { return fallback; }
|
|
}
|
|
|
|
function kindColors() {
|
|
return {
|
|
error: { bg: v("--err-soft", "#fee2e2"), border: v("--err", "#ef4444"), text: v("--err-text", "#7f1d1d") },
|
|
ok: { bg: v("--ok-soft", "#d1fae5"), border: v("--ok", "#10b981"), text: v("--user-text", "#064e3b") },
|
|
warn: { bg: v("--warn-soft", "#fef3c7"), border: v("--warn", "#f59e0b"), text: v("--text", "#0f172a") },
|
|
info: { bg: v("--accent-soft","#e0f2fe"),border: v("--accent","#0ea5e9"),text: v("--bot-text", "#1e3a8a") },
|
|
};
|
|
}
|
|
|
|
let _container = null;
|
|
|
|
function ensureContainer() {
|
|
if (_container) return _container;
|
|
_container = document.createElement("div");
|
|
_container.id = "toast-stack";
|
|
Object.assign(_container.style, {
|
|
position: "fixed",
|
|
right: "16px",
|
|
bottom: "16px",
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
gap: "8px",
|
|
zIndex: "9999",
|
|
pointerEvents: "none",
|
|
maxWidth: "420px",
|
|
});
|
|
document.body.appendChild(_container);
|
|
return _container;
|
|
}
|
|
|
|
export function toast({ kind = "error", text = "", ms = 4000 } = {}) {
|
|
if (!text) return;
|
|
const COLORS = kindColors();
|
|
const colors = COLORS[kind] || COLORS.info;
|
|
const el = document.createElement("div");
|
|
Object.assign(el.style, {
|
|
background: colors.bg,
|
|
border: `1px solid ${colors.border}`,
|
|
color: colors.text,
|
|
padding: "12px 16px",
|
|
borderRadius: "12px",
|
|
fontSize: "13px",
|
|
fontWeight: "500",
|
|
fontFamily: "var(--font-sans, system-ui)",
|
|
boxShadow: "var(--shadow-md, 0 4px 12px rgba(15,23,42,.06))",
|
|
pointerEvents: "auto",
|
|
cursor: "pointer",
|
|
transform: "translateX(120%)",
|
|
transition: "transform .25s ease, opacity .25s ease",
|
|
opacity: "0",
|
|
wordBreak: "break-word",
|
|
overflowWrap: "anywhere",
|
|
});
|
|
el.textContent = String(text);
|
|
|
|
const c = ensureContainer();
|
|
c.appendChild(el);
|
|
|
|
// Animar entrada
|
|
requestAnimationFrame(() => {
|
|
el.style.transform = "translateX(0)";
|
|
el.style.opacity = "1";
|
|
});
|
|
|
|
const dismiss = () => {
|
|
el.style.transform = "translateX(120%)";
|
|
el.style.opacity = "0";
|
|
setTimeout(() => el.remove(), 280);
|
|
};
|
|
el.addEventListener("click", dismiss);
|
|
setTimeout(dismiss, Math.max(800, ms));
|
|
}
|
|
|
|
export function toastError(text) { toast({ kind: "error", text }); }
|
|
export function toastOk(text) { toast({ kind: "ok", text, ms: 2500 }); }
|
|
export function toastWarn(text) { toast({ kind: "warn", text }); }
|