Restyling light pastel: tema blanco/azul/verde + Inter self-hosted

- 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>
This commit is contained in:
Lucas Tettamanti
2026-05-02 13:56:48 -03:00
parent 675a449ce8
commit 0bf26f8eb5
22 changed files with 2355 additions and 655 deletions

View File

@@ -20,45 +20,45 @@ class AliasesCrud extends HTMLElement {
:host { display:block; height:100%; padding:16px; overflow:hidden; } :host { display:block; height:100%; padding:16px; overflow:hidden; }
* { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; } * { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; }
.container { display:grid; grid-template-columns:1fr 1fr; gap:16px; height:100%; } .container { display:grid; grid-template-columns:1fr 1fr; gap:16px; height:100%; }
.panel { background:#121823; border:1px solid #1e2a3a; border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; } .panel { background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; }
.panel-title { font-size:14px; font-weight:700; color:#8aa0b5; text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; } .panel-title { font-size:14px; font-weight:700; color:var(--text-muted); text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; }
.toolbar { display:flex; gap:8px; margin-bottom:12px; } .toolbar { display:flex; gap:8px; margin-bottom:12px; }
input, select, textarea { background:#0f1520; color:#e7eef7; border:1px solid #253245; border-radius:8px; padding:8px 12px; font-size:13px; width:100%; } input, select, textarea { background:var(--panel-2); color:var(--text); border:1px solid var(--border-hi); border-radius:8px; padding:8px 12px; font-size:13px; width:100%; }
input:focus, select:focus, textarea:focus { outline:none; border-color:#1f6feb; } input:focus, select:focus, textarea:focus { outline:none; border-color:var(--accent); }
button { cursor:pointer; background:#1f6feb; color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; } button { cursor:pointer; background:var(--accent); color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; }
button:hover { background:#1a5fd0; } button:hover { background:var(--accent-hover); }
button:disabled { opacity:.5; cursor:not-allowed; } button:disabled { opacity:.5; cursor:not-allowed; }
button.secondary { background:#253245; } button.secondary { background:var(--border-hi); }
button.secondary:hover { background:#2d3e52; } button.secondary:hover { background:var(--border-hi); }
button.danger { background:#e74c3c; } button.danger { background:var(--err); }
button.danger:hover { background:#c0392b; } button.danger:hover { background:var(--err); }
button.small { padding:4px 8px; font-size:11px; } button.small { padding:4px 8px; font-size:11px; }
.list { flex:1; overflow-y:auto; } .list { flex:1; overflow-y:auto; }
.item { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; } .item { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; }
.item:hover { border-color:#1f6feb; } .item:hover { border-color:var(--accent); }
.item.active { border-color:#1f6feb; background:#111b2a; } .item.active { border-color:var(--accent); background:var(--accent-soft); }
.item-alias { font-weight:600; color:#e7eef7; margin-bottom:4px; font-size:15px; } .item-alias { font-weight:600; color:var(--text); margin-bottom:4px; font-size:15px; }
.item-products { font-size:12px; color:#8aa0b5; } .item-products { font-size:12px; color:var(--text-muted); }
.item-boost { color:#2ecc71; font-size:11px; } .item-boost { color:var(--ok); font-size:11px; }
.form { flex:1; overflow-y:auto; } .form { flex:1; overflow-y:auto; }
.form-empty { color:#8aa0b5; text-align:center; padding:40px; } .form-empty { color:var(--text-muted); text-align:center; padding:40px; }
.field { margin-bottom:16px; } .field { margin-bottom:16px; }
.field label { display:block; font-size:12px; color:#8aa0b5; margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; } .field label { display:block; font-size:12px; color:var(--text-muted); margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; }
.field-hint { font-size:11px; color:#8aa0b5; margin-top:4px; } .field-hint { font-size:11px; color:var(--text-muted); margin-top:4px; }
.actions { display:flex; gap:8px; margin-top:16px; } .actions { display:flex; gap:8px; margin-top:16px; }
.loading { text-align:center; padding:40px; color:#8aa0b5; } .loading { text-align:center; padding:40px; color:var(--text-muted); }
/* Product mappings table */ /* Product mappings table */
.mappings-table { width:100%; border-collapse:collapse; margin-top:8px; } .mappings-table { width:100%; border-collapse:collapse; margin-top:8px; }
.mappings-table th { text-align:left; font-size:11px; color:#8aa0b5; padding:8px 4px; border-bottom:1px solid #253245; } .mappings-table th { text-align:left; font-size:11px; color:var(--text-muted); padding:8px 4px; border-bottom:1px solid var(--border-hi); }
.mappings-table td { padding:6px 4px; border-bottom:1px solid #1e2a3a; vertical-align:middle; } .mappings-table td { padding:6px 4px; border-bottom:1px solid var(--border); vertical-align:middle; }
.mappings-table input[type="number"] { width:70px; padding:6px 8px; font-size:12px; } .mappings-table input[type="number"] { width:70px; padding:6px 8px; font-size:12px; }
.mappings-table .product-name { font-size:13px; color:#e7eef7; } .mappings-table .product-name { font-size:13px; color:var(--text); }
.mappings-table .btn-remove { background:#e74c3c; padding:4px 8px; font-size:11px; } .mappings-table .btn-remove { background:var(--err); padding:4px 8px; font-size:11px; }
.add-mapping-row { display:flex; gap:8px; margin-top:12px; align-items:flex-end; } .add-mapping-row { display:flex; gap:8px; margin-top:12px; align-items:flex-end; }
.add-mapping-row .field { margin-bottom:0; } .add-mapping-row .field { margin-bottom:0; }
@@ -67,19 +67,19 @@ class AliasesCrud extends HTMLElement {
.product-selector { position:relative; } .product-selector { position:relative; }
.product-dropdown { .product-dropdown {
position:absolute; top:100%; left:0; right:0; z-index:100; position:absolute; top:100%; left:0; right:0; z-index:100;
background:#0f1520; border:1px solid #253245; border-radius:8px; background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px;
max-height:200px; overflow-y:auto; display:none; max-height:200px; overflow-y:auto; display:none;
} }
.product-dropdown.open { display:block; } .product-dropdown.open { display:block; }
.product-option { .product-option {
padding:8px 12px; cursor:pointer; font-size:13px; color:#e7eef7; padding:8px 12px; cursor:pointer; font-size:13px; color:var(--text);
display:flex; justify-content:space-between; align-items:center; display:flex; justify-content:space-between; align-items:center;
} }
.product-option:hover { background:#1a2535; } .product-option:hover { background:var(--panel-2); }
.product-option .price { font-size:11px; color:#8aa0b5; } .product-option .price { font-size:11px; color:var(--text-muted); }
.empty-hint { color:#8aa0b5; font-size:12px; font-style:italic; } .empty-hint { color:var(--text-muted); font-size:12px; font-style:italic; }
.badge { display:inline-block; padding:2px 6px; border-radius:999px; font-size:10px; background:#253245; color:#8aa0b5; margin-left:4px; } .badge { display:inline-block; padding:2px 6px; border-radius:999px; font-size:10px; background:var(--border-hi); color:var(--text-muted); margin-left:4px; }
</style> </style>
<div class="container"> <div class="container">

View File

@@ -11,25 +11,49 @@ class ChatSimulator extends HTMLElement {
this._sending = false; this._sending = false;
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<style> <style>
:host { display:block; height:100%; overflow:hidden; } :host { display:block; height:100%; overflow:hidden; font-family: var(--font-sans); background: var(--panel); }
* { box-sizing:border-box; } * { box-sizing:border-box; }
.container { display:grid; grid-template-columns:1fr 1fr; gap:0; height:100%; min-height:0; overflow:hidden; } .container { display:grid; grid-template-columns:1fr 1fr; gap:0; height:100%; min-height:0; overflow:hidden; }
.col { display:flex; flex-direction:column; padding:10px 12px; border-right:1px solid var(--border); min-width:0; min-height:0; overflow:hidden; } .col {
display:flex; flex-direction:column;
padding: var(--space-4) var(--space-5);
border-right: 1px solid var(--border);
min-width:0; min-height:0; overflow:hidden;
}
.col:last-child { border-right:none; } .col:last-child { border-right:none; }
.muted { color:var(--text-muted); font-size:11px; margin-bottom:6px; } .muted { color: var(--text-muted); font-size: var(--fs-xs); margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.06em; font-weight: var(--fw-semibold); }
.row { display:flex; gap:8px; align-items:center; } .row { display:flex; gap: var(--space-2); align-items:center; }
input,textarea,button { background:var(--panel-2); color:var(--text); border:1px solid var(--border-hi); border-radius:var(--r-sm); padding:6px 8px; font-size:12px; box-sizing:border-box; } input, textarea, button, select {
background: var(--panel);
color: var(--text);
border: 1px solid var(--border-hi);
border-radius: var(--r-md);
padding: 8px 12px;
font: 400 var(--fs-sm)/1.4 var(--font-sans);
box-sizing:border-box;
transition: border-color .15s, box-shadow .15s;
}
input:focus, textarea:focus, select:focus { outline: none; border-color: var(--accent); box-shadow: var(--focus-ring); }
input { width:100%; min-width:0; } input { width:100%; min-width:0; }
textarea { width:100%; resize:vertical; min-height:120px; max-height:60vh; min-width:0; margin-bottom:10px; word-break:break-word; overflow-wrap:anywhere; } textarea {
button { cursor:pointer; white-space:nowrap; } width:100%; resize:vertical;
button.primary { background:var(--accent); border-color:var(--accent); } min-height:120px; max-height:60vh;
button:disabled { opacity:.6; cursor:not-allowed; } min-width:0; margin-bottom: var(--space-3);
.status { font-size:11px; color:var(--text-muted); margin-top:6px; word-break:break-word; } word-break:break-word; overflow-wrap:anywhere;
.inputs-col { display:flex; flex-direction:column; gap:6px; flex:1; min-height:0; min-width:0; overflow-y:auto; padding-right:4px; } font-family: var(--font-mono);
font-size: var(--fs-sm);
}
button { cursor:pointer; white-space:nowrap; font-weight: var(--fw-medium); }
button:hover:not(:disabled) { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-hover); }
button.primary { background: var(--accent); border-color: var(--accent); color: var(--text-on-acc); }
button.primary:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--text-on-acc); }
button:disabled { opacity:.5; cursor:not-allowed; }
.status { font-size: var(--fs-xs); color: var(--text-muted); margin-top: 8px; word-break:break-word; }
.inputs-col { display:flex; flex-direction:column; gap: 10px; flex:1; min-height:0; min-width:0; overflow-y:auto; padding-right: 4px; }
.field { display:flex; flex-direction:column; min-width:0; } .field { display:flex; flex-direction:column; min-width:0; }
.field label { font-size:10px; color:var(--text-muted); margin-bottom:2px; } .field label { font-size: var(--fs-xs); color: var(--text-muted); margin-bottom: 4px; font-weight: var(--fw-medium); }
.msg-col { display:flex; flex-direction:column; min-width:0; min-height:0; flex:1; } .msg-col { display:flex; flex-direction:column; min-width:0; min-height:0; flex:1; }
.msg-bottom { display:flex; gap:8px; align-items:center; margin-top:6px; flex-wrap:wrap; } .msg-bottom { display:flex; gap: var(--space-2); align-items:center; margin-top: 8px; flex-wrap:wrap; }
</style> </style>
<div class="container"> <div class="container">

View File

@@ -19,29 +19,61 @@ class ConversationInspector extends HTMLElement {
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<style> <style>
:host { display:block; padding:12px; height:100%; overflow:hidden; } :host { display:block; padding: var(--space-4); height:100%; overflow:hidden; font-family: var(--font-sans); }
.box { background:var(--panel); border:1px solid var(--border); border-radius:var(--r-lg); padding:10px; height:100%; display:flex; flex-direction:column; min-height:0; box-sizing:border-box; } .box {
.row { display:flex; gap:8px; align-items:center; } background: var(--panel);
.muted { color:var(--text-muted); font-size:12px; } border: 1px solid var(--border);
.title { font-weight:800; } border-radius: var(--r-lg);
.toolbar { display:flex; gap:8px; margin-top:8px; align-items:center; } padding: var(--space-5);
button { cursor:pointer; background:var(--panel-2); color:var(--text); border:1px solid var(--border-hi); border-radius:var(--r-md); padding:8px; font-size:13px; } height:100%; display:flex; flex-direction:column; min-height:0; box-sizing:border-box;
.list { display:flex; flex-direction:column; gap:0; overflow-y:auto; padding-right:6px; margin-top:8px; flex:1; min-height:0; } box-shadow: var(--shadow-sm);
.item { border:1px solid var(--border-hi); border-radius:12px; padding:8px 10px; background:var(--panel-2); font-size:12px; margin-bottom:12px; box-sizing:border-box; } }
.item.in { background:var(--panel-2); border-color:var(--bot-border); } .row { display:flex; gap: var(--space-2); align-items:center; }
.muted { color: var(--text-muted); font-size: var(--fs-sm); }
.title { font-weight: var(--fw-semibold); font-size: var(--fs-md); color: var(--text); }
.toolbar { display:flex; gap: var(--space-2); margin-top: var(--space-3); align-items:center; }
button {
cursor:pointer;
background: var(--panel); color: var(--text);
border: 1px solid var(--border-hi);
border-radius: var(--r-md);
padding: 6px 12px;
font: var(--fw-medium) var(--fs-sm)/1 var(--font-sans);
transition: all .15s;
}
button:hover { border-color: var(--accent); color: var(--accent-hover); background: var(--accent-soft); }
button:focus-visible { outline:none; box-shadow: var(--focus-ring); }
.list { display:flex; flex-direction:column; gap:0; overflow-y:auto; padding-right: 8px; margin-top: var(--space-3); flex:1; min-height:0; }
.item {
border: 1px solid var(--border);
border-radius: var(--r-lg);
padding: 10px 12px;
background: var(--panel-2);
font-size: var(--fs-sm);
margin-bottom: var(--space-3);
box-sizing:border-box;
transition: border-color .15s;
}
.item.in { background: var(--panel-2); border-color: var(--border); }
.item.out { background: var(--bot-bubble); border-color: var(--bot-border); } .item.out { background: var(--bot-bubble); border-color: var(--bot-border); }
.item.active { outline:2px solid var(--accent); box-shadow: 0 0 0 2px rgba(31,111,235,.25); } .item.active { outline: 2px solid var(--accent); outline-offset: 1px; }
.item-row { display:flex; gap:8px; } .item-row { display:flex; gap: var(--space-2); }
.item-left { flex:1; min-width:0; } .item-left { flex:1; min-width:0; }
.item-right { display:flex; flex-direction:column; gap: 4px; align-items:flex-end; justify-content:flex-start; min-width:60px; } .item-right { display:flex; flex-direction:column; gap: 4px; align-items:flex-end; justify-content:flex-start; min-width:60px; }
.kv { display:grid; grid-template-columns:55px 1fr; gap:4px 6px; } .kv { display:grid; grid-template-columns: 60px 1fr; gap: 4px 8px; }
.k { color:var(--text-muted); font-size:10px; letter-spacing:.3px; text-transform:uppercase; } .k { color: var(--text-muted); font-size: 10px; letter-spacing: 0.06em; text-transform:uppercase; font-weight: var(--fw-semibold); }
.v { font-size:11px; color:var(--text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; } .v { font-size: var(--fs-xs); color: var(--text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.chips { display:flex; flex-direction:column; gap:3px; align-items:flex-end; } .chips { display:flex; flex-direction:column; gap: 4px; align-items:flex-end; }
.chip { display:inline-flex; align-items:center; gap:3px; padding:2px 5px; border-radius:999px; background:#1d2a3a; border:1px solid #243247; font-size:9px; color:var(--text-muted); white-space:nowrap; } .chip {
display:inline-flex; align-items:center; gap: 4px;
padding: 3px 8px; border-radius:999px;
background: var(--panel); border: 1px solid var(--border);
font-size: 10px; color: var(--text-muted); white-space:nowrap;
font-weight: var(--fw-medium);
}
.chip .dot { flex-shrink:0; } .chip .dot { flex-shrink:0; }
.cart { margin-top:4px; font-size:10px; color:var(--bot-name); line-height:1.3; } .cart { margin-top: 6px; font-size: 11px; color: var(--bot-name); line-height: var(--lh-base); }
.tool { margin-top:6px; font-size:11px; color:var(--text-muted); } .tool { margin-top: 8px; font-size: var(--fs-xs); color: var(--text-muted); }
.dot { width:8px; height:8px; border-radius:50%; } .dot { width:8px; height:8px; border-radius:50%; }
.ok { background: var(--ok); } .warn { background: var(--warn); } .err { background: var(--err); } .ok { background: var(--ok); } .warn { background: var(--warn); } .err { background: var(--err); }
</style> </style>

View File

@@ -14,27 +14,68 @@ class ConversationList extends HTMLElement {
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<style> <style>
:host { display:block; padding:12px; } :host { display:block; padding: var(--space-4); font-family: var(--font-sans); }
.box { background:var(--panel); border:1px solid var(--border); border-radius:var(--r-lg); padding:10px; margin-bottom:10px; } .box {
.row { display:flex; gap:8px; align-items:center; } background: var(--panel);
input,select,button { background:var(--panel-2); color:var(--text); border:1px solid var(--border-hi); border-radius:var(--r-md); padding:8px; font-size:13px; } border: 1px solid var(--border);
button { cursor:pointer; } border-radius: var(--r-lg);
button.ghost { background:transparent; } padding: var(--space-4);
button:disabled { opacity:.6; cursor:not-allowed; } margin-bottom: var(--space-3);
.tabs { display:flex; gap:8px; margin-bottom:10px; } box-shadow: var(--shadow-sm);
.tab { flex:1; text-align:center; padding:8px; border-radius:var(--r-md); border:1px solid var(--border-hi); cursor:pointer; color:var(--text-muted); background:var(--panel); } }
.tab.active { border-color:var(--accent); color:var(--text); background:var(--panel-2); } .row { display:flex; gap: var(--space-2); align-items:center; }
.list { display:flex; flex-direction:column; gap:8px; } input, select, button {
.item { background:var(--panel); border:1px solid var(--border); border-radius:var(--r-lg); padding:10px; cursor:pointer; } background: var(--panel);
.item:hover { border-color:#2b3b52; } color: var(--text);
.item.active { border-color:var(--accent); } border: 1px solid var(--border-hi);
.title { font-weight:800; } border-radius: var(--r-md);
.muted { color:var(--text-muted); font-size:12px; } padding: 8px 12px;
font: 400 var(--fs-sm)/1.4 var(--font-sans);
transition: border-color .15s, box-shadow .15s;
}
input:focus, select:focus { outline:none; border-color: var(--accent); box-shadow: var(--focus-ring); }
button { cursor:pointer; font-weight: var(--fw-medium); }
button:hover:not(:disabled) { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-hover); }
button:focus-visible { outline:none; box-shadow: var(--focus-ring); }
button.ghost { background:transparent; border-color: transparent; }
button:disabled { opacity:.5; cursor:not-allowed; }
.tabs { display:flex; gap: var(--space-2); margin-bottom: var(--space-3); }
.tab {
flex:1; text-align:center;
padding: 8px 12px; border-radius: var(--r-md);
border: 1px solid var(--border);
cursor:pointer;
color: var(--text-muted);
background: var(--panel);
font: var(--fw-medium) var(--fs-sm)/1 var(--font-sans);
transition: all .15s;
}
.tab:hover { color: var(--text); }
.tab.active { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.list { display:flex; flex-direction:column; gap: var(--space-2); }
.item {
background: var(--panel);
border: 1px solid var(--border);
border-radius: var(--r-lg);
padding: var(--space-3) var(--space-4);
cursor:pointer;
transition: all .15s;
}
.item:hover { border-color: var(--border-hi); box-shadow: var(--shadow-sm); }
.item.active { border-color: var(--accent); background: var(--accent-soft); }
.title { font-weight: var(--fw-semibold); font-size: var(--fs-base); color: var(--text); }
.muted { color: var(--text-muted); font-size: var(--fs-sm); }
.chips { display:flex; flex-wrap:wrap; gap: 6px; margin-top: 8px; } .chips { display:flex; flex-wrap:wrap; gap: 6px; margin-top: 8px; }
.chip { display:inline-flex; align-items:center; gap:6px; padding:3px 8px; border-radius:999px; background:#1d2a3a; border:1px solid #243247; font-size:12px; color:var(--text-muted); } .chip {
display:inline-flex; align-items:center; gap: 4px;
padding: 3px 8px; border-radius:999px;
background: var(--panel-2); border: 1px solid var(--border);
font-size: var(--fs-xs); color: var(--text-muted);
font-weight: var(--fw-medium);
}
.dot { width:8px; height:8px; border-radius:50%; } .dot { width:8px; height:8px; border-radius:50%; }
.ok{ background: var(--ok) } .warn{ background: var(--warn) } .err{ background: var(--err) } .ok{ background: var(--ok) } .warn{ background: var(--warn) } .err{ background: var(--err) }
.actions { display:flex; gap:8px; justify-content:flex-end; margin-top:8px; flex-wrap:wrap; } .actions { display:flex; gap: var(--space-2); justify-content:flex-end; margin-top: var(--space-2); flex-wrap:wrap; }
</style> </style>
<div class="tabs"> <div class="tabs">

View File

@@ -18,40 +18,40 @@ class ConversationsCrud extends HTMLElement {
:host { display:block; height:100%; padding:16px; overflow:hidden; } :host { display:block; height:100%; padding:16px; overflow:hidden; }
* { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; } * { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; }
.container { display:grid; grid-template-columns:1fr 1fr; gap:16px; height:100%; } .container { display:grid; grid-template-columns:1fr 1fr; gap:16px; height:100%; }
.panel { background:#121823; border:1px solid #1e2a3a; border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; } .panel { background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; }
.panel-title { font-size:14px; font-weight:700; color:#8aa0b5; text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; } .panel-title { font-size:14px; font-weight:700; color:var(--text-muted); text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; }
.toolbar { display:flex; gap:8px; margin-bottom:12px; flex-wrap:wrap; } .toolbar { display:flex; gap:8px; margin-bottom:12px; flex-wrap:wrap; }
input, select { background:#0f1520; color:#e7eef7; border:1px solid #253245; border-radius:8px; padding:8px 12px; font-size:13px; } input, select { background:var(--panel-2); color:var(--text); border:1px solid var(--border-hi); border-radius:8px; padding:8px 12px; font-size:13px; }
input:focus, select:focus { outline:none; border-color:#1f6feb; } input:focus, select:focus { outline:none; border-color:var(--accent); }
button { cursor:pointer; background:#1f6feb; color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; } button { cursor:pointer; background:var(--accent); color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; }
button:hover { background:#1a5fd0; } button:hover { background:var(--accent-hover); }
button:disabled { opacity:.5; cursor:not-allowed; } button:disabled { opacity:.5; cursor:not-allowed; }
button.secondary { background:#253245; } button.secondary { background:var(--border-hi); }
button.secondary:hover { background:#2d3e52; } button.secondary:hover { background:var(--border-hi); }
button.danger { background:#e74c3c; } button.danger { background:var(--err); }
button.danger:hover { background:#c0392b; } button.danger:hover { background:var(--err); }
.list { flex:1; overflow-y:auto; } .list { flex:1; overflow-y:auto; }
.item { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; } .item { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; }
.item:hover { border-color:#1f6feb; } .item:hover { border-color:var(--accent); }
.item.active { border-color:#1f6feb; background:#111b2a; } .item.active { border-color:var(--accent); background:var(--accent-soft); }
.item-header { display:flex; align-items:center; gap:8px; margin-bottom:4px; } .item-header { display:flex; align-items:center; gap:8px; margin-bottom:4px; }
.item-name { font-weight:600; color:#e7eef7; flex:1; } .item-name { font-weight:600; color:var(--text); flex:1; }
.item-meta { font-size:12px; color:#8aa0b5; } .item-meta { font-size:12px; color:var(--text-muted); }
.dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; } .dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
.ok { background:#2ecc71; } .warn { background:#f1c40f; } .err { background:#e74c3c; } .ok { background:var(--ok); } .warn { background:var(--warn); } .err { background:var(--err); }
.chips { display:flex; flex-wrap:wrap; gap:6px; margin-top:6px; } .chips { display:flex; flex-wrap:wrap; gap:6px; margin-top:6px; }
.chip { display:inline-block; padding:2px 8px; border-radius:999px; font-size:11px; background:#253245; color:#8aa0b5; } .chip { display:inline-block; padding:2px 8px; border-radius:999px; font-size:11px; background:var(--border-hi); color:var(--text-muted); }
.detail { flex:1; overflow-y:auto; } .detail { flex:1; overflow-y:auto; }
.detail-empty { color:#8aa0b5; text-align:center; padding:40px; } .detail-empty { color:var(--text-muted); text-align:center; padding:40px; }
.field { margin-bottom:16px; } .field { margin-bottom:16px; }
.field label { display:block; font-size:12px; color:#8aa0b5; margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; } .field label { display:block; font-size:12px; color:var(--text-muted); margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; }
.field-value { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:10px 12px; color:#e7eef7; font-size:13px; } .field-value { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:10px 12px; color:var(--text); font-size:13px; }
.actions { display:flex; gap:8px; margin-top:16px; flex-wrap:wrap; } .actions { display:flex; gap:8px; margin-top:16px; flex-wrap:wrap; }
.loading { text-align:center; padding:40px; color:#8aa0b5; } .loading { text-align:center; padding:40px; color:var(--text-muted); }
</style> </style>
<div class="container"> <div class="container">

View File

@@ -9,12 +9,12 @@ class DebugPanel extends HTMLElement {
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<style> <style>
:host { display:block; padding:12px; } :host { display:block; padding:12px; }
.box { background:#121823; border:1px solid #1e2a3a; border-radius:10px; padding:10px; } .box { background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:10px; }
.muted { color:#8aa0b5; font-size:12px; } .muted { color:var(--text-muted); font-size:12px; }
.kv { display:grid; grid-template-columns:90px 1fr; gap:6px 10px; margin:10px 0 12px; } .kv { display:grid; grid-template-columns:90px 1fr; gap:6px 10px; margin:10px 0 12px; }
.k { color:#8aa0b5; font-size:12px; letter-spacing:.4px; text-transform:uppercase; } .k { color:var(--text-muted); font-size:12px; letter-spacing:.4px; text-transform:uppercase; }
.v { font-size:13px; font-weight:800; color:#e7eef7; } .v { font-size:13px; font-weight:800; color:var(--text); }
pre { white-space:pre-wrap; word-break:break-word; background:#0f1520; border:1px solid #253245; border-radius:10px; padding:10px; margin:0; font-size:12px; color:#d7e2ef; } pre { white-space:pre-wrap; word-break:break-word; background:var(--panel-2); border:1px solid var(--border-hi); border-radius:10px; padding:10px; margin:0; font-size:12px; color:var(--text-dim); }
</style> </style>
<div class="box"> <div class="box">

View File

@@ -10,6 +10,20 @@ function formatNumber(value) {
return new Intl.NumberFormat("es-AR", { maximumFractionDigits: 1 }).format(value); return new Intl.NumberFormat("es-AR", { maximumFractionDigits: 1 }).format(value);
} }
/** Lee una CSS custom property del :root. Fallback al hex provisto. */
function cssVar(name, fallback = "") {
const v = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
return v || fallback;
}
/** rgba con alpha desde un hex (#RRGGBB) o sky/etc — para fills de charts. */
function withAlpha(hex, alpha) {
const m = /^#?([0-9a-f]{6})$/i.exec(hex || "");
if (!m) return hex;
const n = parseInt(m[1], 16);
return `rgba(${(n >> 16) & 255}, ${(n >> 8) & 255}, ${n & 255}, ${alpha})`;
}
class HomeDashboard extends HTMLElement { class HomeDashboard extends HTMLElement {
constructor() { constructor() {
super(); super();
@@ -20,109 +34,86 @@ class HomeDashboard extends HTMLElement {
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<style> <style>
:host { :host { font-family: var(--font-sans); }
/* Aliases locales que apuntan a los globals — los charts usan estos * { box-sizing: border-box; }
nombres cortos. Cambiar el tema desde theme.css se propaga aquí. */
--line: var(--border);
--blue: var(--chart-blue);
--green: var(--chart-green);
--purple: var(--chart-purple);
--orange: var(--chart-orange);
--emerald: #10B981;
--pink: var(--chart-pink);
--gray: var(--chart-gray);
}
* { box-sizing: border-box; font-family: system-ui, Segoe UI, Roboto, Arial; }
.container { .container {
min-height: 100%; min-height: 100%;
background: var(--bg); background: var(--bg);
color: var(--text); color: var(--text);
padding: 16px; padding: var(--space-6);
overflow-y: auto; overflow-y: auto;
} }
.header { .header {
display: flex; display: flex; justify-content: space-between; align-items: baseline;
justify-content: space-between; margin-bottom: var(--space-6);
align-items: center;
margin-bottom: 20px;
} }
.header h1 { .header h1 {
font-size: 24px; font-size: var(--fs-xl);
font-weight: 600; font-weight: var(--fw-semibold);
letter-spacing: -0.02em;
margin: 0; margin: 0;
} }
.sync-info { .sync-info { font-size: var(--fs-sm); color: var(--text-muted); }
font-size: 12px;
color: var(--muted);
}
.grid { .grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 16px; gap: var(--space-6);
} }
.chart-card { .chart-card {
background: var(--panel); background: var(--panel);
border-radius: 8px; border: 1px solid var(--border);
padding: 16px; border-radius: var(--r-lg);
} padding: var(--space-5);
.chart-card.full-width { box-shadow: var(--shadow-sm);
grid-column: 1 / -1;
} }
.chart-card.full-width { grid-column: 1 / -1; }
.chart-title { .chart-title {
font-size: 14px; font-size: var(--fs-xs);
font-weight: 600; font-weight: var(--fw-semibold);
color: var(--muted); color: var(--text-muted);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.5px; letter-spacing: 0.06em;
margin-bottom: 12px; margin-bottom: var(--space-4);
}
.chart-container {
position: relative;
height: 250px;
}
.chart-container.tall {
height: 300px;
}
.chart-container.short {
height: 200px;
} }
.chart-container { position: relative; height: 260px; }
.chart-container.tall { height: 320px; }
.chart-container.short { height: 200px; }
.loading { .loading {
display: flex; display: flex; align-items: center; justify-content: center;
align-items: center; height: 200px; color: var(--text-muted);
justify-content: center;
height: 200px;
color: var(--muted);
} }
.kpi-row { .kpi-row {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 16px; gap: var(--space-4);
margin-bottom: 20px; margin-bottom: var(--space-6);
} }
.kpi-card { .kpi-card {
background: var(--panel); background: var(--panel);
border-radius: 8px; border: 1px solid var(--border);
padding: 16px; border-radius: var(--r-lg);
text-align: center; padding: var(--space-5);
box-shadow: var(--shadow-sm);
} }
.kpi-value { .kpi-value {
font-size: 24px; font-size: var(--fs-xl);
font-weight: 700; font-weight: var(--fw-bold);
letter-spacing: -0.02em;
margin-bottom: 4px; margin-bottom: 4px;
} }
.kpi-label { .kpi-label {
font-size: 12px; font-size: var(--fs-xs);
color: var(--muted); color: var(--text-muted);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em;
font-weight: var(--fw-medium);
} }
.donut-row { .donut-row {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px; gap: var(--space-4);
}
canvas {
max-width: 100%;
} }
canvas { max-width: 100%; }
</style> </style>
<div class="container"> <div class="container">
<div class="header"> <div class="header">
@@ -236,7 +227,7 @@ class HomeDashboard extends HTMLElement {
const kpiRow = this.shadowRoot.querySelector(".kpi-row"); const kpiRow = this.shadowRoot.querySelector(".kpi-row");
kpiRow.innerHTML = ` kpiRow.innerHTML = `
<div class="kpi-card"> <div class="kpi-card">
<div class="kpi-value" style="color: var(--blue)">${formatCurrency(totals.total_revenue)}</div> <div class="kpi-value" style="color: var(--chart-blue)">${formatCurrency(totals.total_revenue)}</div>
<div class="kpi-label">Total Facturado</div> <div class="kpi-label">Total Facturado</div>
</div> </div>
<div class="kpi-card"> <div class="kpi-card">
@@ -244,11 +235,11 @@ class HomeDashboard extends HTMLElement {
<div class="kpi-label">Pedidos</div> <div class="kpi-label">Pedidos</div>
</div> </div>
<div class="kpi-card"> <div class="kpi-card">
<div class="kpi-value" style="color: var(--green)">${formatCurrency(totals.by_source?.whatsapp)}</div> <div class="kpi-value" style="color: var(--chart-green)">${formatCurrency(totals.by_source?.whatsapp)}</div>
<div class="kpi-label">WhatsApp</div> <div class="kpi-label">WhatsApp</div>
</div> </div>
<div class="kpi-card"> <div class="kpi-card">
<div class="kpi-value" style="color: var(--blue)">${formatCurrency(totals.by_source?.web)}</div> <div class="kpi-value" style="color: var(--chart-blue)">${formatCurrency(totals.by_source?.web)}</div>
<div class="kpi-label">Web</div> <div class="kpi-label">Web</div>
</div> </div>
`; `;
@@ -273,8 +264,8 @@ class HomeDashboard extends HTMLElement {
datasets: [{ datasets: [{
label: "Ventas", label: "Ventas",
data: totals, data: totals,
backgroundColor: "rgba(59, 130, 246, 0.8)", backgroundColor: withAlpha(cssVar("--chart-blue"), 0.7),
borderColor: "#3b82f6", borderColor: cssVar("--chart-blue"),
borderWidth: 1, borderWidth: 1,
}], }],
}, },
@@ -287,11 +278,11 @@ class HomeDashboard extends HTMLElement {
scales: { scales: {
y: { y: {
beginAtZero: true, beginAtZero: true,
ticks: { color: "#8aa0b5" }, ticks: { color: cssVar("--text-muted") },
grid: { color: "#1e2a3a" }, grid: { color: cssVar("--border") },
}, },
x: { x: {
ticks: { color: "#8aa0b5" }, ticks: { color: cssVar("--text-muted") },
grid: { display: false }, grid: { display: false },
}, },
}, },
@@ -320,12 +311,12 @@ class HomeDashboard extends HTMLElement {
{ {
label: "WhatsApp", label: "WhatsApp",
data: waData, data: waData,
backgroundColor: "#25D366", backgroundColor: cssVar("--chart-green"),
}, },
{ {
label: "Web", label: "Web",
data: webData, data: webData,
backgroundColor: "#3b82f6", backgroundColor: cssVar("--chart-blue"),
}, },
], ],
}, },
@@ -335,19 +326,19 @@ class HomeDashboard extends HTMLElement {
plugins: { plugins: {
legend: { legend: {
position: "top", position: "top",
labels: { color: "#8aa0b5" }, labels: { color: cssVar("--text-muted") },
}, },
}, },
scales: { scales: {
y: { y: {
stacked: true, stacked: true,
beginAtZero: true, beginAtZero: true,
ticks: { color: "#8aa0b5" }, ticks: { color: cssVar("--text-muted") },
grid: { color: "#1e2a3a" }, grid: { color: cssVar("--border") },
}, },
x: { x: {
stacked: true, stacked: true,
ticks: { color: "#8aa0b5" }, ticks: { color: cssVar("--text-muted") },
grid: { display: false }, grid: { display: false },
}, },
}, },
@@ -371,16 +362,16 @@ class HomeDashboard extends HTMLElement {
{ {
label: String(yoy.current_year || "Actual"), label: String(yoy.current_year || "Actual"),
data: yoy.current_year_data || [], data: yoy.current_year_data || [],
borderColor: "#3b82f6", borderColor: cssVar("--chart-blue"),
backgroundColor: "rgba(59, 130, 246, 0.1)", backgroundColor: withAlpha(cssVar("--chart-blue"), 0.15),
fill: true, fill: true,
tension: 0.3, tension: 0.3,
}, },
{ {
label: String(yoy.last_year || "Anterior"), label: String(yoy.last_year || "Anterior"),
data: yoy.last_year_data || [], data: yoy.last_year_data || [],
borderColor: "#9CA3AF", borderColor: cssVar("--chart-gray"),
backgroundColor: "rgba(156, 163, 175, 0.1)", backgroundColor: withAlpha(cssVar("--chart-gray"), 0.15),
fill: true, fill: true,
tension: 0.3, tension: 0.3,
}, },
@@ -392,17 +383,17 @@ class HomeDashboard extends HTMLElement {
plugins: { plugins: {
legend: { legend: {
position: "top", position: "top",
labels: { color: "#8aa0b5" }, labels: { color: cssVar("--text-muted") },
}, },
}, },
scales: { scales: {
y: { y: {
beginAtZero: true, beginAtZero: true,
ticks: { color: "#8aa0b5" }, ticks: { color: cssVar("--text-muted") },
grid: { color: "#1e2a3a" }, grid: { color: cssVar("--border") },
}, },
x: { x: {
ticks: { color: "#8aa0b5" }, ticks: { color: cssVar("--text-muted") },
grid: { display: false }, grid: { display: false },
}, },
}, },
@@ -423,7 +414,7 @@ class HomeDashboard extends HTMLElement {
labels: ["WhatsApp", "Web"], labels: ["WhatsApp", "Web"],
datasets: [{ datasets: [{
data: [totals.by_source?.whatsapp || 0, totals.by_source?.web || 0], data: [totals.by_source?.whatsapp || 0, totals.by_source?.web || 0],
backgroundColor: ["#25D366", "#3b82f6"], backgroundColor: [cssVar("--chart-green"), cssVar("--chart-blue")],
}], }],
}, },
options: this.getDonutOptions(), options: this.getDonutOptions(),
@@ -440,7 +431,7 @@ class HomeDashboard extends HTMLElement {
labels: ["Delivery", "Retiro"], labels: ["Delivery", "Retiro"],
datasets: [{ datasets: [{
data: [totals.by_shipping?.delivery || 0, totals.by_shipping?.pickup || 0], data: [totals.by_shipping?.delivery || 0, totals.by_shipping?.pickup || 0],
backgroundColor: ["#8B5CF6", "#F59E0B"], backgroundColor: [cssVar("--chart-purple"), cssVar("--chart-orange")],
}], }],
}, },
options: this.getDonutOptions(), options: this.getDonutOptions(),
@@ -456,7 +447,7 @@ class HomeDashboard extends HTMLElement {
plugins: { plugins: {
legend: { legend: {
position: "bottom", position: "bottom",
labels: { color: "#8aa0b5" }, labels: { color: cssVar("--text-muted") },
}, },
}, },
}; };
@@ -479,8 +470,8 @@ class HomeDashboard extends HTMLElement {
datasets: [{ datasets: [{
label: "Facturación", label: "Facturación",
data, data,
backgroundColor: "rgba(59, 130, 246, 0.8)", backgroundColor: withAlpha(cssVar("--chart-blue"), 0.7),
borderColor: "#3b82f6", borderColor: cssVar("--chart-blue"),
borderWidth: 1, borderWidth: 1,
}], }],
}, },
@@ -494,11 +485,11 @@ class HomeDashboard extends HTMLElement {
scales: { scales: {
x: { x: {
beginAtZero: true, beginAtZero: true,
ticks: { color: "#8aa0b5" }, ticks: { color: cssVar("--text-muted") },
grid: { color: "#1e2a3a" }, grid: { color: cssVar("--border") },
}, },
y: { y: {
ticks: { color: "#8aa0b5" }, ticks: { color: cssVar("--text-muted") },
grid: { display: false }, grid: { display: false },
}, },
}, },
@@ -523,8 +514,8 @@ class HomeDashboard extends HTMLElement {
datasets: [{ datasets: [{
label: "Kg", label: "Kg",
data, data,
backgroundColor: "rgba(139, 92, 246, 0.8)", backgroundColor: withAlpha(cssVar("--chart-purple"), 0.7),
borderColor: "#8B5CF6", borderColor: cssVar("--chart-purple"),
borderWidth: 1, borderWidth: 1,
}], }],
}, },
@@ -538,11 +529,11 @@ class HomeDashboard extends HTMLElement {
scales: { scales: {
x: { x: {
beginAtZero: true, beginAtZero: true,
ticks: { color: "#8aa0b5" }, ticks: { color: cssVar("--text-muted") },
grid: { color: "#1e2a3a" }, grid: { color: cssVar("--border") },
}, },
y: { y: {
ticks: { color: "#8aa0b5", font: { size: 10 } }, ticks: { color: cssVar("--text-muted"), font: { size: 10 } },
grid: { display: false }, grid: { display: false },
}, },
}, },
@@ -567,8 +558,8 @@ class HomeDashboard extends HTMLElement {
datasets: [{ datasets: [{
label: "Unidades", label: "Unidades",
data, data,
backgroundColor: "rgba(245, 158, 11, 0.8)", backgroundColor: withAlpha(cssVar("--chart-orange"), 0.7),
borderColor: "#F59E0B", borderColor: cssVar("--chart-orange"),
borderWidth: 1, borderWidth: 1,
}], }],
}, },
@@ -582,11 +573,11 @@ class HomeDashboard extends HTMLElement {
scales: { scales: {
x: { x: {
beginAtZero: true, beginAtZero: true,
ticks: { color: "#8aa0b5" }, ticks: { color: cssVar("--text-muted") },
grid: { color: "#1e2a3a" }, grid: { color: cssVar("--border") },
}, },
y: { y: {
ticks: { color: "#8aa0b5", font: { size: 10 } }, ticks: { color: cssVar("--text-muted"), font: { size: 10 } },
grid: { display: false }, grid: { display: false },
}, },
}, },

View File

@@ -12,39 +12,69 @@ class OpsShell extends HTMLElement {
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<style> <style>
:host { --bg:#0b0f14; --panel:#121823; --muted:#8aa0b5; --text:#e7eef7; --line:#1e2a3a; --blue:#1f6feb; } * { box-sizing:border-box; }
* { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; } :host { font-family: var(--font-sans); }
.app { height:100vh; background:var(--bg); color:var(--text); display:flex; flex-direction:column; } .app { height:100vh; background:var(--bg); color:var(--text); display:flex; flex-direction:column; }
header { display:flex; gap:12px; align-items:center; padding:12px 16px; border-bottom:1px solid var(--line); flex-wrap:wrap; } header {
header h1 { font-size:14px; margin:0; color:var(--muted); font-weight:700; letter-spacing:.4px; text-transform:uppercase; } display:flex; gap:var(--space-3); align-items:center;
.nav { display:flex; gap:4px; margin-left:24px; flex-wrap:wrap; } padding: var(--space-3) var(--space-6);
.nav-btn { background:transparent; border:1px solid var(--line); color:var(--muted); padding:6px 12px; border-radius:6px; font-size:12px; cursor:pointer; transition:all .15s; text-decoration:none; } background: var(--panel);
.nav-btn:hover { border-color:var(--blue); color:var(--text); } border-bottom: 1px solid var(--border);
.nav-btn.active { background:var(--blue); border-color:var(--blue); color:#fff; } flex-wrap:wrap;
}
header h1 {
font-size: var(--fs-md);
margin:0; color: var(--text);
font-weight: var(--fw-semibold);
letter-spacing:-0.01em;
}
.nav { display:flex; gap: var(--space-1); margin-left: var(--space-6); flex-wrap:wrap; }
.nav-btn {
position:relative;
background:transparent; border:none;
color: var(--text-muted);
padding: 8px 12px;
font: var(--fw-medium) var(--fs-sm)/1 var(--font-sans);
cursor:pointer; transition:color .15s;
text-decoration:none;
border-radius: var(--r-sm);
}
.nav-btn:hover { color: var(--text); background: var(--panel-2); }
.nav-btn.active { color: var(--accent); background: var(--accent-soft); }
.nav-btn:focus-visible { outline:none; box-shadow: var(--focus-ring); }
.spacer { flex:1; } .spacer { flex:1; }
.status { font-size:12px; color:var(--muted); display:flex; align-items:center; gap:6px; } .status {
.status .dot { width:8px; height:8px; border-radius:50%; background:#25D366; } font-size: var(--fs-sm); color: var(--ok);
.status.disconnected .dot { background:#F59E0B; animation: pulse 1.2s ease-in-out infinite; } display:flex; align-items:center; gap: 6px;
.status.disconnected { color:#F59E0B; } padding: 4px 10px;
@keyframes pulse { 0%,100% { opacity:1; } 50% { opacity:.35; } } background: var(--ok-soft);
border-radius: 999px;
}
.status .dot { width:7px; height:7px; border-radius:50%; background: var(--ok); }
.status.disconnected { color: var(--warn); background: var(--warn-soft); }
.status.disconnected .dot { background: var(--warn); animation: pulse 1.2s ease-in-out infinite; }
@keyframes pulse { 0%,100% { opacity:1; } 50% { opacity:.4; } }
/* Notification bell */ /* Notification bell */
.notification-bell { position:relative; cursor:pointer; padding:8px; margin-right:12px; } .notification-bell { position:relative; cursor:pointer; padding: 8px; border-radius: var(--r-sm); transition: background .15s; }
.notification-bell svg { width:20px; height:20px; fill:var(--muted); transition:fill .15s; } .notification-bell:hover { background: var(--panel-2); }
.notification-bell svg { width:18px; height:18px; fill: var(--text-muted); transition:fill .15s; display:block; }
.notification-bell:hover svg { fill: var(--text); } .notification-bell:hover svg { fill: var(--text); }
.notification-bell.has-pending svg { fill:#f39c12; } .notification-bell.has-pending svg { fill: var(--warn); }
.notification-bell .badge { .notification-bell .badge {
position:absolute; top:2px; right:2px; position:absolute; top:2px; right:2px;
background:#e74c3c; color:#fff; background: var(--err); color:#fff;
font-size:10px; padding:2px 6px; border-radius:10px; font: var(--fw-bold) 10px/1 var(--font-sans);
font-weight:700; min-width:18px; text-align:center; padding: 3px 6px; border-radius:10px;
min-width:18px; text-align:center;
box-shadow: 0 0 0 2px var(--panel);
} }
/* Layout para chat activo (2 columnas: burbujas + inspector) */ /* Layout para chat activo (2 columnas: burbujas + inspector) */
.layout-chat { height:100%; display:grid; grid-template-columns:1fr 1fr; grid-template-rows:1fr 310px; min-height:0; overflow:hidden; } .layout-chat { height:100%; display:grid; grid-template-columns:1fr 1fr; grid-template-rows:1fr 310px; min-height:0; overflow:hidden; }
.col { border-right:1px solid var(--line); min-height:0; overflow:hidden; } .col { border-right:1px solid var(--border); min-height:0; overflow:hidden; }
.chatTop { grid-column:1; grid-row:1; border-bottom:1px solid var(--line); } .chatTop { grid-column:1; grid-row:1; border-bottom:1px solid var(--border); }
.chatBottom { grid-column:1 / 3; grid-row:2; overflow:hidden; border-top:1px solid var(--line); } .chatBottom { grid-column:1 / 3; grid-row:2; overflow:hidden; border-top:1px solid var(--border); }
.inspectorTop { grid-column:2; grid-row:1; border-right:none; } .inspectorTop { grid-column:2; grid-row:1; border-right:none; }
/* Layout para CRUDs */ /* Layout para CRUDs */

View File

@@ -23,15 +23,15 @@ function statusLabel(status) {
function statusColor(status) { function statusColor(status) {
const map = { const map = {
pending: "#f59e0b", pending: "var(--warn)",
processing: "#3b82f6", processing: "var(--chart-blue)",
"on-hold": "#8b5cf6", "on-hold": "var(--chart-purple)",
completed: "#22c55e", completed: "var(--ok)",
cancelled: "#6b7280", cancelled: "var(--text-muted)",
refunded: "#ec4899", refunded: "var(--chart-pink)",
failed: "#ef4444", failed: "var(--err)",
}; };
return map[status] || "#8aa0b5"; return map[status] || "var(--text-muted)";
} }
class OrdersCrud extends HTMLElement { class OrdersCrud extends HTMLElement {
@@ -51,15 +51,15 @@ class OrdersCrud extends HTMLElement {
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<style> <style>
:host { :host {
--bg: #0b0f14; --bg: var(--bg);
--panel: #121823; --panel: var(--panel);
--muted: #8aa0b5; --muted: var(--text-muted);
--text: #e7eef7; --text: var(--text);
--line: #1e2a3a; --line: var(--border);
--blue: #1f6feb; --blue: var(--accent);
--green: #238636; --green: var(--ok);
--red: #da3633; --red: var(--err);
--orange: #f59e0b; --orange: var(--warn);
} }
* { box-sizing: border-box; font-family: system-ui, Segoe UI, Roboto, Arial; } * { box-sizing: border-box; font-family: system-ui, Segoe UI, Roboto, Arial; }
.container { .container {
@@ -154,10 +154,10 @@ class OrdersCrud extends HTMLElement {
font-weight: 600; font-weight: 600;
text-transform: uppercase; text-transform: uppercase;
} }
.badge.test { background: var(--orange); color: #000; } .badge.test { background: var(--orange); color: var(--text); }
.badge.real { background: var(--green); color: #fff; } .badge.real { background: var(--green); color: #fff; }
.badge.whatsapp { background: #25d366; color: #fff; } .badge.whatsapp { background: var(--ok); color: #fff; }
.badge.web { background: var(--muted); color: #000; } .badge.web { background: var(--muted); color: var(--text); }
.status-badge { .status-badge {
padding: 3px 8px; padding: 3px 8px;
border-radius: 4px; border-radius: 4px;
@@ -451,7 +451,7 @@ class OrdersCrud extends HTMLElement {
</div> </div>
</td> </td>
<td><span class="status-badge" style="background:${statusColor(order.status)}">${statusLabel(order.status)}</span></td> <td><span class="status-badge" style="background:${statusColor(order.status)}">${statusLabel(order.status)}</span></td>
<td><span class="badge" style="background:${order.is_delivery ? '#3b82f6' : '#8b5cf6'};color:#fff">${order.is_delivery ? 'DEL' : 'RET'}</span></td> <td><span class="badge" style="background:${order.is_delivery ? 'var(--chart-blue)' : 'var(--chart-purple)'};color:#fff">${order.is_delivery ? 'DEL' : 'RET'}</span></td>
<td class="customer-name" title="${customerName}">${customerName}</td> <td class="customer-name" title="${customerName}">${customerName}</td>
<td class="total">$${Number(order.total || 0).toLocaleString("es-AR")}</td> <td class="total">$${Number(order.total || 0).toLocaleString("es-AR")}</td>
<td>${formatDate(order.date_created)}</td> <td>${formatDate(order.date_created)}</td>
@@ -558,7 +558,7 @@ class OrdersCrud extends HTMLElement {
<div class="detail-row"> <div class="detail-row">
<span class="detail-label">Método</span> <span class="detail-label">Método</span>
<span class="detail-value"> <span class="detail-value">
<span class="badge ${order.is_delivery ? 'delivery' : 'pickup'}" style="background:${order.is_delivery ? '#3b82f6' : '#8b5cf6'};color:#fff;padding:3px 8px;border-radius:4px;font-size:10px;"> <span class="badge ${order.is_delivery ? 'delivery' : 'pickup'}" style="background:${order.is_delivery ? 'var(--chart-blue)' : 'var(--chart-purple)'};color:#fff;padding:3px 8px;border-radius:4px;font-size:10px;">
${order.is_delivery ? 'DELIVERY' : 'RETIRO'} ${order.is_delivery ? 'DELIVERY' : 'RETIRO'}
</span> </span>
${order.shipping_method ? `<span style="margin-left:8px;color:var(--muted);font-size:11px;">${order.shipping_method}</span>` : ''} ${order.shipping_method ? `<span style="margin-left:8px;color:var(--muted);font-size:11px;">${order.shipping_method}</span>` : ''}

View File

@@ -19,46 +19,46 @@ class ProductsCrud extends HTMLElement {
:host { display:block; height:100%; padding:16px; overflow:hidden; } :host { display:block; height:100%; padding:16px; overflow:hidden; }
* { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; } * { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; }
.container { display:grid; grid-template-columns:1fr 1fr; gap:16px; height:100%; } .container { display:grid; grid-template-columns:1fr 1fr; gap:16px; height:100%; }
.panel { background:#121823; border:1px solid #1e2a3a; border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; } .panel { background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; }
.panel-title { font-size:14px; font-weight:700; color:#8aa0b5; text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; } .panel-title { font-size:14px; font-weight:700; color:var(--text-muted); text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; }
.toolbar { display:flex; gap:8px; margin-bottom:12px; } .toolbar { display:flex; gap:8px; margin-bottom:12px; }
input, select { background:#0f1520; color:#e7eef7; border:1px solid #253245; border-radius:8px; padding:8px 12px; font-size:13px; } input, select { background:var(--panel-2); color:var(--text); border:1px solid var(--border-hi); border-radius:8px; padding:8px 12px; font-size:13px; }
input:focus, select:focus { outline:none; border-color:#1f6feb; } input:focus, select:focus { outline:none; border-color:var(--accent); }
input { flex:1; } input { flex:1; }
button { cursor:pointer; background:#1f6feb; color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; } button { cursor:pointer; background:var(--accent); color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; }
button:hover { background:#1a5fd0; } button:hover { background:var(--accent-hover); }
button:disabled { opacity:.5; cursor:not-allowed; } button:disabled { opacity:.5; cursor:not-allowed; }
button.secondary { background:#253245; } button.secondary { background:var(--border-hi); }
button.secondary:hover { background:#2d3e52; } button.secondary:hover { background:var(--border-hi); }
.list { flex:1; overflow-y:auto; } .list { flex:1; overflow-y:auto; }
.item { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; user-select:none; } .item { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; user-select:none; }
.item:hover { border-color:#1f6feb; } .item:hover { border-color:var(--accent); }
.item.active { border-color:#1f6feb; background:#111b2a; } .item.active { border-color:var(--accent); background:var(--accent-soft); }
.item.selected { border-color:#2ecc71; background:#0f2a1a; } .item.selected { border-color:var(--ok); background:var(--ok-soft); }
.item-name { font-weight:600; color:#e7eef7; margin-bottom:4px; } .item-name { font-weight:600; color:var(--text); margin-bottom:4px; }
.item-meta { font-size:12px; color:#8aa0b5; } .item-meta { font-size:12px; color:var(--text-muted); }
.item-price { color:#2ecc71; font-weight:600; } .item-price { color:var(--ok); font-weight:600; }
.detail { flex:1; overflow-y:auto; } .detail { flex:1; overflow-y:auto; }
.detail-empty { color:#8aa0b5; text-align:center; padding:40px; } .detail-empty { color:var(--text-muted); text-align:center; padding:40px; }
.field { margin-bottom:16px; } .field { margin-bottom:16px; }
.field label { display:block; font-size:12px; color:#8aa0b5; margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; } .field label { display:block; font-size:12px; color:var(--text-muted); margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; }
.field-value { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:10px 12px; color:#e7eef7; font-size:13px; } .field-value { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:10px 12px; color:var(--text); font-size:13px; }
.field-value.json { font-family:monospace; font-size:11px; white-space:pre-wrap; max-height:200px; overflow-y:auto; } .field-value.json { font-family:monospace; font-size:11px; white-space:pre-wrap; max-height:200px; overflow-y:auto; }
.stats { display:flex; gap:16px; margin-bottom:16px; } .stats { display:flex; gap:16px; margin-bottom:16px; }
.stat { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:12px; flex:1; text-align:center; cursor:pointer; transition:all .15s; } .stat { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:12px; flex:1; text-align:center; cursor:pointer; transition:all .15s; }
.stat:hover { border-color:#1f6feb; } .stat:hover { border-color:var(--accent); }
.stat.active { border-color:#1f6feb; background:#111b2a; } .stat.active { border-color:var(--accent); background:var(--accent-soft); }
.stat-value { font-size:24px; font-weight:700; color:#1f6feb; } .stat-value { font-size:24px; font-weight:700; color:var(--accent); }
.stat-label { font-size:11px; color:#8aa0b5; text-transform:uppercase; margin-top:4px; } .stat-label { font-size:11px; color:var(--text-muted); text-transform:uppercase; margin-top:4px; }
.loading { text-align:center; padding:40px; color:#8aa0b5; } .loading { text-align:center; padding:40px; color:var(--text-muted); }
.badge { display:inline-block; padding:2px 8px; border-radius:999px; font-size:11px; background:#253245; color:#8aa0b5; margin-left:8px; } .badge { display:inline-block; padding:2px 8px; border-radius:999px; font-size:11px; background:var(--border-hi); color:var(--text-muted); margin-left:8px; }
.badge.stock { background:#0f2a1a; color:#2ecc71; } .badge.stock { background:var(--ok-soft); color:var(--ok); }
.badge.nostock { background:#241214; color:#e74c3c; } .badge.nostock { background:var(--err-soft); color:var(--err); }
</style> </style>
<div class="container"> <div class="container">
@@ -272,7 +272,7 @@ class ProductsCrud extends HTMLElement {
// Mostrar unidad actual si está definida // Mostrar unidad actual si está definida
const unit = item.sell_unit || item.payload?._sell_unit_override; const unit = item.sell_unit || item.payload?._sell_unit_override;
const unitBadge = unit ? `<span class="badge" style="background:#1a3a5c;color:#7eb8e7;">${unit === 'unit' ? 'Unidad' : 'Kg'}</span>` : ''; const unitBadge = unit ? `<span class="badge" style="background:var(--accent-soft);color:var(--accent-hover);">${unit === 'unit' ? 'Unidad' : 'Kg'}</span>` : '';
el.innerHTML = ` el.innerHTML = `
<div class="item-name">${item.name || "Sin nombre"} ${stockBadge} ${unitBadge}</div> <div class="item-name">${item.name || "Sin nombre"} ${stockBadge} ${unitBadge}</div>
@@ -328,7 +328,7 @@ class ProductsCrud extends HTMLElement {
} catch (err) { } catch (err) {
console.error("[products-crud] Error in renderDetail:", err); console.error("[products-crud] Error in renderDetail:", err);
const detail = this.shadowRoot.getElementById("detail"); const detail = this.shadowRoot.getElementById("detail");
detail.innerHTML = `<div class="detail-empty" style="color:#e74c3c;">Error: ${err.message}</div>`; detail.innerHTML = `<div class="detail-empty" style="color:var(--err);">Error: ${err.message}</div>`;
} }
// Scroll detail panel to top // Scroll detail panel to top
@@ -449,12 +449,12 @@ class ProductsCrud extends HTMLElement {
<div class="field"> <div class="field">
<label>Unidad de venta</label> <label>Unidad de venta</label>
<div style="display:flex;gap:8px;align-items:center;"> <div style="display:flex;gap:8px;align-items:center;">
<select id="sellUnit" style="background:#0f1520;color:#e7eef7;border:1px solid #253245;border-radius:8px;padding:8px 12px;font-size:13px;"> <select id="sellUnit" style="background:var(--panel-2);color:var(--text);border:1px solid var(--border-hi);border-radius:8px;padding:8px 12px;font-size:13px;">
<option value="kg" ${currentUnit === "kg" ? "selected" : ""}>Por peso (kg)</option> <option value="kg" ${currentUnit === "kg" ? "selected" : ""}>Por peso (kg)</option>
<option value="unit" ${currentUnit === "unit" ? "selected" : ""}>Por unidad</option> <option value="unit" ${currentUnit === "unit" ? "selected" : ""}>Por unidad</option>
</select> </select>
</div> </div>
<div style="font-size:11px;color:#8aa0b5;margin-top:4px;"> <div style="font-size:11px;color:var(--text-muted);margin-top:4px;">
Define si este producto se vende por peso o por unidad Define si este producto se vende por peso o por unidad
</div> </div>
</div> </div>
@@ -464,16 +464,16 @@ class ProductsCrud extends HTMLElement {
${categoriesArray.length > 0 ${categoriesArray.length > 0
? categoriesArray.map(cat => ` ? categoriesArray.map(cat => `
<span class="category-tag" data-category="${this.escapeHtml(cat)}" <span class="category-tag" data-category="${this.escapeHtml(cat)}"
style="display:inline-flex;align-items:center;gap:4px;background:#1a3a5c;color:#7eb8e7;padding:4px 8px;border-radius:6px;font-size:12px;"> style="display:inline-flex;align-items:center;gap:4px;background:var(--accent-soft);color:var(--accent-hover);padding:4px 8px;border-radius:6px;font-size:12px;">
${this.escapeHtml(cat)} ${this.escapeHtml(cat)}
<span class="remove-cat" style="cursor:pointer;font-weight:bold;opacity:0.7;">&times;</span> <span class="remove-cat" style="cursor:pointer;font-weight:bold;opacity:0.7;">&times;</span>
</span> </span>
`).join("") `).join("")
: '<span style="color:#8aa0b5;font-size:12px;">Sin categorías</span>' : '<span style="color:var(--text-muted);font-size:12px;">Sin categorías</span>'
} }
</div> </div>
<div style="display:flex;gap:8px;align-items:center;"> <div style="display:flex;gap:8px;align-items:center;">
<select id="addCategorySelect" style="background:#0f1520;color:#e7eef7;border:1px solid #253245;border-radius:8px;padding:8px 12px;font-size:13px;flex:1;"> <select id="addCategorySelect" style="background:var(--panel-2);color:var(--text);border:1px solid var(--border-hi);border-radius:8px;padding:8px 12px;font-size:13px;flex:1;">
<option value="">-- Agregar categoría --</option> <option value="">-- Agregar categoría --</option>
${this.getAllCategories().filter(c => !categoriesArray.includes(c)).map(cat => ${this.getAllCategories().filter(c => !categoriesArray.includes(c)).map(cat =>
`<option value="${this.escapeHtml(cat)}">${this.escapeHtml(cat)}</option>` `<option value="${this.escapeHtml(cat)}">${this.escapeHtml(cat)}</option>`
@@ -489,7 +489,7 @@ class ProductsCrud extends HTMLElement {
<div class="field"> <div class="field">
<div style="display:flex;gap:8px;align-items:center;"> <div style="display:flex;gap:8px;align-items:center;">
<button id="saveProduct" style="flex:1;padding:10px;">Guardar cambios</button> <button id="saveProduct" style="flex:1;padding:10px;">Guardar cambios</button>
<span id="saveStatus" style="font-size:12px;color:#2ecc71;"></span> <span id="saveStatus" style="font-size:12px;color:var(--ok);"></span>
</div> </div>
</div> </div>
<div class="field"> <div class="field">
@@ -533,7 +533,7 @@ class ProductsCrud extends HTMLElement {
const tag = document.createElement("span"); const tag = document.createElement("span");
tag.className = "category-tag"; tag.className = "category-tag";
tag.dataset.category = categoryName; tag.dataset.category = categoryName;
tag.style = "display:inline-flex;align-items:center;gap:4px;background:#1a3a5c;color:#7eb8e7;padding:4px 8px;border-radius:6px;font-size:12px;"; tag.style = "display:inline-flex;align-items:center;gap:4px;background:var(--accent-soft);color:var(--accent-hover);padding:4px 8px;border-radius:6px;font-size:12px;";
tag.innerHTML = `${this.escapeHtml(categoryName)}<span class="remove-cat" style="cursor:pointer;font-weight:bold;opacity:0.7;">&times;</span>`; tag.innerHTML = `${this.escapeHtml(categoryName)}<span class="remove-cat" style="cursor:pointer;font-weight:bold;opacity:0.7;">&times;</span>`;
// Bind remove // Bind remove
@@ -545,7 +545,7 @@ class ProductsCrud extends HTMLElement {
}; };
// Remover el mensaje "Sin categorías" si existe // Remover el mensaje "Sin categorías" si existe
const emptyMsg = container.querySelector('span[style*="color:#8aa0b5"]'); const emptyMsg = container.querySelector('span[style*="color:var(--text-muted)"]');
if (emptyMsg) emptyMsg.remove(); if (emptyMsg) emptyMsg.remove();
container.appendChild(tag); container.appendChild(tag);
@@ -652,8 +652,8 @@ class ProductsCrud extends HTMLElement {
detail.innerHTML = ` detail.innerHTML = `
<div class="field"> <div class="field">
<label>Productos seleccionados</label> <label>Productos seleccionados</label>
<div class="field-value" style="color:#2ecc71;font-weight:600;">${count} productos</div> <div class="field-value" style="color:var(--ok);font-weight:600;">${count} productos</div>
<div style="font-size:11px;color:#8aa0b5;margin-top:4px;">${names}${moreText}</div> <div style="font-size:11px;color:var(--text-muted);margin-top:4px;">${names}${moreText}</div>
<div style="font-size:11px;margin-top:4px;"> <div style="font-size:11px;margin-top:4px;">
<span class="badge stock" style="margin-left:0;">${inStockCount} en stock</span> <span class="badge stock" style="margin-left:0;">${inStockCount} en stock</span>
<span class="badge nostock">${count - inStockCount} sin stock</span> <span class="badge nostock">${count - inStockCount} sin stock</span>
@@ -662,26 +662,26 @@ class ProductsCrud extends HTMLElement {
<div class="field"> <div class="field">
<label>Unidad de venta (para todos)</label> <label>Unidad de venta (para todos)</label>
<div style="display:flex;gap:8px;align-items:center;"> <div style="display:flex;gap:8px;align-items:center;">
<select id="sellUnit" style="background:#0f1520;color:#e7eef7;border:1px solid #253245;border-radius:8px;padding:8px 12px;font-size:13px;flex:1;"> <select id="sellUnit" style="background:var(--panel-2);color:var(--text);border:1px solid var(--border-hi);border-radius:8px;padding:8px 12px;font-size:13px;flex:1;">
<option value="kg">Por peso (kg)</option> <option value="kg">Por peso (kg)</option>
<option value="unit">Por unidad</option> <option value="unit">Por unidad</option>
</select> </select>
<button id="saveUnit" style="padding:8px 16px;">Aplicar</button> <button id="saveUnit" style="padding:8px 16px;">Aplicar</button>
</div> </div>
<div style="font-size:11px;color:#8aa0b5;margin-top:4px;"> <div style="font-size:11px;color:var(--text-muted);margin-top:4px;">
Se aplicará a todos los productos seleccionados Se aplicará a todos los productos seleccionados
</div> </div>
</div> </div>
<div class="field"> <div class="field">
<label>Agregar categoría (para todos)</label> <label>Agregar categoría (para todos)</label>
<div style="display:flex;gap:8px;align-items:center;"> <div style="display:flex;gap:8px;align-items:center;">
<select id="addCategorySelect" style="background:#0f1520;color:#e7eef7;border:1px solid #253245;border-radius:8px;padding:8px 12px;font-size:13px;flex:1;"> <select id="addCategorySelect" style="background:var(--panel-2);color:var(--text);border:1px solid var(--border-hi);border-radius:8px;padding:8px 12px;font-size:13px;flex:1;">
<option value="">-- Seleccionar categoría --</option> <option value="">-- Seleccionar categoría --</option>
${this.getAllCategories().map(cat => `<option value="${this.escapeHtml(cat)}">${this.escapeHtml(cat)}</option>`).join("")} ${this.getAllCategories().map(cat => `<option value="${this.escapeHtml(cat)}">${this.escapeHtml(cat)}</option>`).join("")}
</select> </select>
<button id="addCategory" style="padding:8px 16px;">Agregar</button> <button id="addCategory" style="padding:8px 16px;">Agregar</button>
</div> </div>
<div style="font-size:11px;color:#8aa0b5;margin-top:4px;"> <div style="font-size:11px;color:var(--text-muted);margin-top:4px;">
Se agregará esta categoría a todos los productos seleccionados Se agregará esta categoría a todos los productos seleccionados
</div> </div>
</div> </div>

View File

@@ -28,47 +28,47 @@ class QuantitiesCrud extends HTMLElement {
:host { display:block; height:100%; padding:16px; overflow:hidden; } :host { display:block; height:100%; padding:16px; overflow:hidden; }
* { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; } * { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; }
.container { display:grid; grid-template-columns:1fr 1fr; gap:16px; height:100%; } .container { display:grid; grid-template-columns:1fr 1fr; gap:16px; height:100%; }
.panel { background:#121823; border:1px solid #1e2a3a; border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; } .panel { background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; }
.panel-title { font-size:14px; font-weight:700; color:#8aa0b5; text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; } .panel-title { font-size:14px; font-weight:700; color:var(--text-muted); text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; }
.toolbar { display:flex; gap:8px; margin-bottom:12px; } .toolbar { display:flex; gap:8px; margin-bottom:12px; }
input, select { background:#0f1520; color:#e7eef7; border:1px solid #253245; border-radius:8px; padding:8px 12px; font-size:13px; width:100%; } input, select { background:var(--panel-2); color:var(--text); border:1px solid var(--border-hi); border-radius:8px; padding:8px 12px; font-size:13px; width:100%; }
input:focus, select:focus { outline:none; border-color:#1f6feb; } input:focus, select:focus { outline:none; border-color:var(--accent); }
button { cursor:pointer; background:#1f6feb; color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; } button { cursor:pointer; background:var(--accent); color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; }
button:hover { background:#1a5fd0; } button:hover { background:var(--accent-hover); }
button:disabled { opacity:.5; cursor:not-allowed; } button:disabled { opacity:.5; cursor:not-allowed; }
button.secondary { background:#253245; } button.secondary { background:var(--border-hi); }
button.secondary:hover { background:#2d3e52; } button.secondary:hover { background:var(--border-hi); }
.list { flex:1; overflow-y:auto; } .list { flex:1; overflow-y:auto; }
.item { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; display:flex; justify-content:space-between; align-items:center; } .item { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; display:flex; justify-content:space-between; align-items:center; }
.item:hover { border-color:#1f6feb; } .item:hover { border-color:var(--accent); }
.item.active { border-color:#1f6feb; background:#111b2a; } .item.active { border-color:var(--accent); background:var(--accent-soft); }
.item-name { font-weight:500; color:#e7eef7; } .item-name { font-weight:500; color:var(--text); }
.item-price { font-size:12px; color:#8aa0b5; } .item-price { font-size:12px; color:var(--text-muted); }
.badge { display:inline-flex; align-items:center; justify-content:center; min-width:20px; height:20px; padding:0 6px; border-radius:999px; font-size:11px; font-weight:600; background:#1f6feb; color:#fff; } .badge { display:inline-flex; align-items:center; justify-content:center; min-width:20px; height:20px; padding:0 6px; border-radius:999px; font-size:11px; font-weight:600; background:var(--accent); color:#fff; }
.badge.empty { background:#253245; color:#8aa0b5; } .badge.empty { background:var(--border-hi); color:var(--text-muted); }
.form { flex:1; overflow-y:auto; } .form { flex:1; overflow-y:auto; }
.form-empty { color:#8aa0b5; text-align:center; padding:40px; } .form-empty { color:var(--text-muted); text-align:center; padding:40px; }
.product-header { margin-bottom:16px; } .product-header { margin-bottom:16px; }
.product-name { font-size:18px; font-weight:600; color:#e7eef7; margin-bottom:4px; } .product-name { font-size:18px; font-weight:600; color:var(--text); margin-bottom:4px; }
.product-price { font-size:14px; color:#8aa0b5; } .product-price { font-size:14px; color:var(--text-muted); }
.qty-grid { width:100%; border-collapse:collapse; } .qty-grid { width:100%; border-collapse:collapse; }
.qty-grid th { text-align:left; font-size:12px; color:#8aa0b5; padding:10px 8px; border-bottom:1px solid #253245; } .qty-grid th { text-align:left; font-size:12px; color:var(--text-muted); padding:10px 8px; border-bottom:1px solid var(--border-hi); }
.qty-grid td { padding:8px; border-bottom:1px solid #1e2a3a; } .qty-grid td { padding:8px; border-bottom:1px solid var(--border); }
.qty-grid .event-label { font-size:13px; color:#e7eef7; font-weight:500; } .qty-grid .event-label { font-size:13px; color:var(--text); font-weight:500; }
.qty-grid input { width:70px; padding:6px 8px; font-size:12px; text-align:center; } .qty-grid input { width:70px; padding:6px 8px; font-size:12px; text-align:center; }
.qty-grid select { width:70px; padding:6px 4px; font-size:11px; } .qty-grid select { width:70px; padding:6px 4px; font-size:11px; }
.cell-group { display:flex; gap:4px; align-items:center; } .cell-group { display:flex; gap:4px; align-items:center; }
.actions { display:flex; gap:8px; margin-top:16px; } .actions { display:flex; gap:8px; margin-top:16px; }
.loading { text-align:center; padding:40px; color:#8aa0b5; } .loading { text-align:center; padding:40px; color:var(--text-muted); }
.status { font-size:12px; color:#2ecc71; margin-left:auto; } .status { font-size:12px; color:var(--ok); margin-left:auto; }
.status.error { color:#e74c3c; } .status.error { color:var(--err); }
</style> </style>
<div class="container"> <div class="container">

View File

@@ -40,45 +40,45 @@ class RecommendationsCrud extends HTMLElement {
:host { display:block; height:100%; padding:16px; overflow:hidden; } :host { display:block; height:100%; padding:16px; overflow:hidden; }
* { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; } * { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; }
.container { display:grid; grid-template-columns:1fr 1fr; gap:16px; height:100%; } .container { display:grid; grid-template-columns:1fr 1fr; gap:16px; height:100%; }
.panel { background:#121823; border:1px solid #1e2a3a; border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; } .panel { background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; }
.panel-title { font-size:14px; font-weight:700; color:#8aa0b5; text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; } .panel-title { font-size:14px; font-weight:700; color:var(--text-muted); text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; }
.toolbar { display:flex; gap:8px; margin-bottom:12px; } .toolbar { display:flex; gap:8px; margin-bottom:12px; }
input, select, textarea { background:#0f1520; color:#e7eef7; border:1px solid #253245; border-radius:8px; padding:8px 12px; font-size:13px; width:100%; } input, select, textarea { background:var(--panel-2); color:var(--text); border:1px solid var(--border-hi); border-radius:8px; padding:8px 12px; font-size:13px; width:100%; }
input:focus, select:focus, textarea:focus { outline:none; border-color:#1f6feb; } input:focus, select:focus, textarea:focus { outline:none; border-color:var(--accent); }
textarea { min-height:60px; resize:vertical; font-size:13px; } textarea { min-height:60px; resize:vertical; font-size:13px; }
button { cursor:pointer; background:#1f6feb; color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; } button { cursor:pointer; background:var(--accent); color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; }
button:hover { background:#1a5fd0; } button:hover { background:var(--accent-hover); }
button:disabled { opacity:.5; cursor:not-allowed; } button:disabled { opacity:.5; cursor:not-allowed; }
button.secondary { background:#253245; } button.secondary { background:var(--border-hi); }
button.secondary:hover { background:#2d3e52; } button.secondary:hover { background:var(--border-hi); }
button.danger { background:#e74c3c; } button.danger { background:var(--err); }
button.danger:hover { background:#c0392b; } button.danger:hover { background:var(--err); }
button.small { padding:4px 8px; font-size:11px; } button.small { padding:4px 8px; font-size:11px; }
.list { flex:1; overflow-y:auto; } .list { flex:1; overflow-y:auto; }
.item { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; } .item { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; }
.item:hover { border-color:#1f6feb; } .item:hover { border-color:var(--accent); }
.item.active { border-color:#1f6feb; background:#111b2a; } .item.active { border-color:var(--accent); background:var(--accent-soft); }
.item-key { font-weight:600; color:#e7eef7; margin-bottom:4px; display:flex; align-items:center; gap:8px; } .item-key { font-weight:600; color:var(--text); margin-bottom:4px; display:flex; align-items:center; gap:8px; }
.item-trigger { font-size:12px; color:#8aa0b5; margin-bottom:4px; } .item-trigger { font-size:12px; color:var(--text-muted); margin-bottom:4px; }
.item-queries { font-size:11px; color:#2ecc71; } .item-queries { font-size:11px; color:var(--ok); }
.badge { display:inline-block; padding:2px 8px; border-radius:999px; font-size:10px; } .badge { display:inline-block; padding:2px 8px; border-radius:999px; font-size:10px; }
.badge.active { background:#0f2a1a; color:#2ecc71; } .badge.active { background:var(--ok-soft); color:var(--ok); }
.badge.inactive { background:#241214; color:#e74c3c; } .badge.inactive { background:var(--err-soft); color:var(--err); }
.badge.priority { background:#253245; color:#8aa0b5; } .badge.priority { background:var(--border-hi); color:var(--text-muted); }
.badge.type { background:#1a2a4a; color:#5dade2; } .badge.type { background:var(--accent-soft); color:var(--accent-hover); }
.form { flex:1; overflow-y:auto; } .form { flex:1; overflow-y:auto; }
.form-empty { color:#8aa0b5; text-align:center; padding:40px; } .form-empty { color:var(--text-muted); text-align:center; padding:40px; }
.field { margin-bottom:16px; } .field { margin-bottom:16px; }
.field label { display:block; font-size:12px; color:#8aa0b5; margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; } .field label { display:block; font-size:12px; color:var(--text-muted); margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; }
.field-hint { font-size:11px; color:#8aa0b5; margin-top:4px; } .field-hint { font-size:11px; color:var(--text-muted); margin-top:4px; }
.field-row { display:flex; gap:12px; } .field-row { display:flex; gap:12px; }
.field-row .field { flex:1; } .field-row .field { flex:1; }
.actions { display:flex; gap:8px; margin-top:16px; } .actions { display:flex; gap:8px; margin-top:16px; }
.loading { text-align:center; padding:40px; color:#8aa0b5; } .loading { text-align:center; padding:40px; color:var(--text-muted); }
.toggle { display:flex; align-items:center; gap:8px; cursor:pointer; } .toggle { display:flex; align-items:center; gap:8px; cursor:pointer; }
.toggle input { width:auto; } .toggle input { width:auto; }
@@ -88,42 +88,42 @@ class RecommendationsCrud extends HTMLElement {
.product-search { margin-bottom:8px; } .product-search { margin-bottom:8px; }
.product-dropdown { .product-dropdown {
position:absolute; top:100%; left:0; right:0; z-index:100; position:absolute; top:100%; left:0; right:0; z-index:100;
background:#0f1520; border:1px solid #253245; border-radius:8px; background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px;
max-height:200px; overflow-y:auto; display:none; max-height:200px; overflow-y:auto; display:none;
} }
.product-dropdown.open { display:block; } .product-dropdown.open { display:block; }
.product-option { .product-option {
padding:8px 12px; cursor:pointer; font-size:13px; color:#e7eef7; padding:8px 12px; cursor:pointer; font-size:13px; color:var(--text);
display:flex; justify-content:space-between; align-items:center; display:flex; justify-content:space-between; align-items:center;
} }
.product-option:hover { background:#1a2535; } .product-option:hover { background:var(--panel-2); }
.product-option.selected { background:#1a3a5c; } .product-option.selected { background:var(--accent-soft); }
.product-option .price { font-size:11px; color:#8aa0b5; } .product-option .price { font-size:11px; color:var(--text-muted); }
.selected-products { display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; min-height:30px; } .selected-products { display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; min-height:30px; }
.product-chip { .product-chip {
display:inline-flex; align-items:center; gap:4px; display:inline-flex; align-items:center; gap:4px;
background:#253245; color:#e7eef7; padding:4px 8px 4px 12px; background:var(--border-hi); color:var(--text); padding:4px 8px 4px 12px;
border-radius:999px; font-size:12px; border-radius:999px; font-size:12px;
} }
.product-chip .remove { .product-chip .remove {
cursor:pointer; width:16px; height:16px; border-radius:50%; cursor:pointer; width:16px; height:16px; border-radius:50%;
background:#e74c3c; color:#fff; font-size:10px; background:var(--err); color:#fff; font-size:10px;
display:flex; align-items:center; justify-content:center; display:flex; align-items:center; justify-content:center;
} }
.product-chip .remove:hover { background:#c0392b; } .product-chip .remove:hover { background:var(--err); }
.empty-hint { color:#8aa0b5; font-size:12px; font-style:italic; } .empty-hint { color:var(--text-muted); font-size:12px; font-style:italic; }
/* Items table styles */ /* Items table styles */
.items-table { width:100%; border-collapse:collapse; margin-top:8px; } .items-table { width:100%; border-collapse:collapse; margin-top:8px; }
.items-table th { text-align:left; font-size:11px; color:#8aa0b5; padding:8px 4px; border-bottom:1px solid #253245; } .items-table th { text-align:left; font-size:11px; color:var(--text-muted); padding:8px 4px; border-bottom:1px solid var(--border-hi); }
.items-table td { padding:6px 4px; border-bottom:1px solid #1e2a3a; vertical-align:middle; } .items-table td { padding:6px 4px; border-bottom:1px solid var(--border); vertical-align:middle; }
.items-table input { padding:6px 8px; font-size:12px; } .items-table input { padding:6px 8px; font-size:12px; }
.items-table input[type="number"] { width:70px; } .items-table input[type="number"] { width:70px; }
.items-table select { padding:6px 8px; font-size:12px; width:80px; } .items-table select { padding:6px 8px; font-size:12px; width:80px; }
.items-table .product-name { font-size:13px; color:#e7eef7; } .items-table .product-name { font-size:13px; color:var(--text); }
.items-table .btn-remove { background:#e74c3c; padding:4px 8px; font-size:11px; } .items-table .btn-remove { background:var(--err); padding:4px 8px; font-size:11px; }
.add-item-row { display:flex; gap:8px; margin-top:12px; align-items:flex-end; } .add-item-row { display:flex; gap:8px; margin-top:12px; align-items:flex-end; }
.add-item-row .field { margin-bottom:0; } .add-item-row .field { margin-bottom:0; }
@@ -131,12 +131,12 @@ class RecommendationsCrud extends HTMLElement {
/* Rule type selector */ /* Rule type selector */
.rule-type-selector { display:flex; gap:8px; margin-bottom:16px; } .rule-type-selector { display:flex; gap:8px; margin-bottom:16px; }
.rule-type-btn { .rule-type-btn {
flex:1; padding:12px; border:2px solid #253245; border-radius:8px; flex:1; padding:12px; border:2px solid var(--border-hi); border-radius:8px;
background:#0f1520; color:#8aa0b5; cursor:pointer; text-align:center; background:var(--panel-2); color:var(--text-muted); cursor:pointer; text-align:center;
transition:all .15s; transition:all .15s;
} }
.rule-type-btn:hover { border-color:#1f6feb; } .rule-type-btn:hover { border-color:var(--accent); }
.rule-type-btn.active { border-color:#1f6feb; background:#111b2a; color:#e7eef7; } .rule-type-btn.active { border-color:var(--accent); background:var(--accent-soft); color:var(--text); }
.rule-type-btn .type-title { font-weight:600; margin-bottom:4px; } .rule-type-btn .type-title { font-weight:600; margin-bottom:4px; }
.rule-type-btn .type-desc { font-size:11px; } .rule-type-btn .type-desc { font-size:11px; }
</style> </style>

View File

@@ -13,29 +13,68 @@ class RunTimeline extends HTMLElement {
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<style> <style>
:host { display:block; padding:12px; height:100%; overflow:hidden; } :host { display:block; padding: var(--space-4); height:100%; overflow:hidden; font-family: var(--font-sans); }
.box { background:var(--panel); border:1px solid var(--border); border-radius:var(--r-lg); padding:10px; height:100%; display:flex; flex-direction:column; min-height:0; box-sizing:border-box; } .box {
.row { display:flex; gap:8px; align-items:center; } background: var(--panel);
.muted { color:var(--text-muted); font-size:12px; } border: 1px solid var(--border);
.title { font-weight:800; } border-radius: var(--r-lg);
.chatlog { display:flex; flex-direction:column; gap:0; overflow-y:auto; padding-right:6px; margin-top:8px; flex:1; min-height:0; } padding: var(--space-5);
/* WhatsApp-ish dark theme bubbles */ height:100%; display:flex; flex-direction:column; min-height:0; box-sizing:border-box;
.bubble { max-width:90%; min-width:0; margin-bottom:12px; padding:8px 10px; border-radius:var(--r-xl); border:1px solid var(--border-hi); font-size:13px; line-height:1.35; white-space:pre-wrap; word-break:break-word; overflow-wrap:anywhere; box-shadow:var(--shadow-bubble); box-sizing:border-box; } box-shadow: var(--shadow-sm);
.bubble.user { align-self:flex-end; background:var(--user-bubble); border-color:var(--user-border); color:var(--text); } }
.bubble.bot { align-self:flex-start; background:var(--bot-bubble); border-color:var(--bot-border); color:var(--text); } .row { display:flex; gap: var(--space-2); align-items:center; }
.bubble.err { align-self:flex-start; background:var(--err-bubble); border-color:var(--err-border); color:var(--err-meta); cursor:pointer; } .muted { color: var(--text-muted); font-size: var(--fs-sm); }
.bubble.active { outline:2px solid var(--accent); box-shadow: 0 0 0 2px rgba(31,111,235,.25); } .title { font-weight: var(--fw-semibold); font-size: var(--fs-md); color: var(--text); }
.name { display:block; font-size:12px; font-weight:800; margin-bottom:4px; opacity:.95; } .chatlog { display:flex; flex-direction:column; gap:0; overflow-y:auto; padding-right:8px; margin-top: var(--space-3); flex:1; min-height:0; }
/* WhatsApp-ish light pastel bubbles */
.bubble {
max-width: 88%; min-width:0;
margin-bottom: var(--space-3);
padding: 10px 14px;
border-radius: var(--r-xl);
border: 1px solid;
font-size: var(--fs-base); line-height: var(--lh-base);
white-space:pre-wrap; word-break:break-word; overflow-wrap:anywhere;
box-shadow: var(--shadow-bubble);
box-sizing:border-box;
}
.bubble.user { align-self:flex-end; background: var(--user-bubble); border-color: var(--user-border); color: var(--user-text); }
.bubble.bot { align-self:flex-start; background: var(--bot-bubble); border-color: var(--bot-border); color: var(--bot-text); }
.bubble.err { align-self:flex-start; background: var(--err-bubble); border-color: var(--err-border); color: var(--err-text); cursor:pointer; }
.bubble.active { outline: 2px solid var(--accent); outline-offset: 1px; }
.name { display:block; font-size: var(--fs-xs); font-weight: var(--fw-semibold); margin-bottom: 4px; letter-spacing: 0.02em; }
.bubble.user .name { color: var(--user-name); text-align:right; } .bubble.user .name { color: var(--user-name); text-align:right; }
.bubble.bot .name { color: var(--bot-name); } .bubble.bot .name { color: var(--bot-name); }
.bubble.err .name { color: var(--err-name); } .bubble.err .name { color: var(--err-name); }
.bubble .meta { display:block; margin-top:6px; font-size:11px; color:var(--text-muted); } .bubble .meta { display:block; margin-top: 6px; font-size: var(--fs-xs); color: var(--text-muted); }
.bubble.user .meta { color:var(--user-meta); opacity:.85; } .bubble.user .meta { color: var(--user-meta); }
.bubble.bot .meta { color:var(--bot-meta); opacity:.85; } .bubble.bot .meta { color: var(--bot-meta); }
.bubble.err .meta { color:var(--err-meta); opacity:.85; } .bubble.err .meta { color: var(--err-meta); }
.toolbar { display:flex; gap:8px; margin-top:8px; align-items:center; }
button { cursor:pointer; background:var(--panel-2); color:var(--text); border:1px solid var(--border-hi); border-radius:var(--r-md); padding:8px; font-size:13px; } .toolbar { display:flex; gap: var(--space-2); margin-top: var(--space-3); align-items:center; }
pre { white-space:pre-wrap; word-break:break-word; overflow-wrap:anywhere; overflow-x:auto; max-width:100%; background:var(--panel-2); border:1px solid var(--border-hi); border-radius:var(--r-lg); padding:10px; margin:0; font-size:12px; color:var(--text-dim); } button {
cursor:pointer;
background: var(--panel); color: var(--text);
border: 1px solid var(--border-hi);
border-radius: var(--r-md);
padding: 8px 14px;
font: var(--fw-medium) var(--fs-sm)/1 var(--font-sans);
transition: border-color .15s, background .15s;
}
button:hover { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-hover); }
button:focus-visible { outline:none; box-shadow: var(--focus-ring); }
pre {
white-space:pre-wrap; word-break:break-word; overflow-wrap:anywhere; overflow-x:auto; max-width:100%;
background: var(--panel-2);
border: 1px solid var(--border);
border-radius: var(--r-lg);
padding: 10px 12px;
margin:0;
font: 400 12px/1.5 var(--font-mono);
color: var(--text-dim);
}
</style> </style>
<div class="box"> <div class="box">

View File

@@ -37,47 +37,47 @@ class SettingsCrud extends HTMLElement {
:host { display:block; height:100%; padding:16px; overflow:auto; } :host { display:block; height:100%; padding:16px; overflow:auto; }
* { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; } * { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; }
.container { max-width:800px; margin:0 auto; } .container { max-width:800px; margin:0 auto; }
.panel { background:#121823; border:1px solid #1e2a3a; border-radius:10px; padding:20px; margin-bottom:16px; } .panel { background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:20px; margin-bottom:16px; }
.panel-title { font-size:16px; font-weight:700; color:#e7eef7; margin-bottom:16px; display:flex; align-items:center; gap:8px; } .panel-title { font-size:16px; font-weight:700; color:var(--text); margin-bottom:16px; display:flex; align-items:center; gap:8px; }
.panel-title svg { width:20px; height:20px; fill:#1f6feb; } .panel-title svg { width:20px; height:20px; fill:var(--accent); }
.form-row { display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-bottom:16px; } .form-row { display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-bottom:16px; }
.form-row.full { grid-template-columns:1fr; } .form-row.full { grid-template-columns:1fr; }
.field { } .field { }
.field label { display:block; font-size:12px; color:#8aa0b5; margin-bottom:6px; text-transform:uppercase; letter-spacing:.4px; } .field label { display:block; font-size:12px; color:var(--text-muted); margin-bottom:6px; text-transform:uppercase; letter-spacing:.4px; }
.field-hint { font-size:11px; color:#6c7a89; margin-top:4px; } .field-hint { font-size:11px; color:var(--text-muted); margin-top:4px; }
input, select, textarea { input, select, textarea {
background:#0f1520; color:#e7eef7; border:1px solid #253245; background:var(--panel-2); color:var(--text); border:1px solid var(--border-hi);
border-radius:8px; padding:10px 14px; font-size:14px; width:100%; border-radius:8px; padding:10px 14px; font-size:14px; width:100%;
} }
input:focus, select:focus, textarea:focus { outline:none; border-color:#1f6feb; } input:focus, select:focus, textarea:focus { outline:none; border-color:var(--accent); }
input:disabled { opacity:.6; cursor:not-allowed; } input:disabled { opacity:.6; cursor:not-allowed; }
button { button {
cursor:pointer; background:#1f6feb; color:#fff; border:none; cursor:pointer; background:var(--accent); color:#fff; border:none;
border-radius:8px; padding:10px 20px; font-size:14px; font-weight:600; border-radius:8px; padding:10px 20px; font-size:14px; font-weight:600;
} }
button:hover { background:#1a5fd0; } button:hover { background:var(--accent-hover); }
button:disabled { opacity:.5; cursor:not-allowed; } button:disabled { opacity:.5; cursor:not-allowed; }
button.secondary { background:#253245; } button.secondary { background:var(--border-hi); }
button.secondary:hover { background:#2d3e52; } button.secondary:hover { background:var(--border-hi); }
.toggle-row { display:flex; align-items:center; gap:12px; margin-bottom:16px; } .toggle-row { display:flex; align-items:center; gap:12px; margin-bottom:16px; }
.toggle { .toggle {
position:relative; width:48px; height:26px; position:relative; width:48px; height:26px;
background:#253245; border-radius:13px; cursor:pointer; background:var(--border-hi); border-radius:13px; cursor:pointer;
transition:background .2s; flex-shrink:0; transition:background .2s; flex-shrink:0;
} }
.toggle.active { background:#1f6feb; } .toggle.active { background:var(--accent); }
.toggle::after { .toggle::after {
content:''; position:absolute; top:3px; left:3px; content:''; position:absolute; top:3px; left:3px;
width:20px; height:20px; background:#fff; border-radius:50%; width:20px; height:20px; background:#fff; border-radius:50%;
transition:transform .2s; transition:transform .2s;
} }
.toggle.active::after { transform:translateX(22px); } .toggle.active::after { transform:translateX(22px); }
.toggle-label { font-size:14px; color:#e7eef7; } .toggle-label { font-size:14px; color:var(--text); }
/* Schedule grid */ /* Schedule grid */
.schedule-grid { display:flex; flex-direction:column; gap:8px; } .schedule-grid { display:flex; flex-direction:column; gap:8px; }
@@ -87,17 +87,17 @@ class SettingsCrud extends HTMLElement {
gap:12px; gap:12px;
align-items:center; align-items:center;
padding:8px 12px; padding:8px 12px;
background:#0f1520; background:var(--panel-2);
border-radius:8px; border-radius:8px;
border:1px solid #1e2a3a; border:1px solid var(--border);
} }
.schedule-row.disabled { opacity:0.4; } .schedule-row.disabled { opacity:0.4; }
.day-label { font-size:13px; color:#e7eef7; font-weight:500; } .day-label { font-size:13px; color:var(--text); font-weight:500; }
.day-toggle { .day-toggle {
width:32px; height:18px; background:#253245; border-radius:9px; width:32px; height:18px; background:var(--border-hi); border-radius:9px;
cursor:pointer; position:relative; transition:background .2s; cursor:pointer; position:relative; transition:background .2s;
} }
.day-toggle.active { background:#2ecc71; } .day-toggle.active { background:var(--ok); }
.day-toggle::after { .day-toggle::after {
content:''; position:absolute; top:2px; left:2px; content:''; position:absolute; top:2px; left:2px;
width:14px; height:14px; background:#fff; border-radius:50%; width:14px; height:14px; background:#fff; border-radius:50%;
@@ -109,30 +109,30 @@ class SettingsCrud extends HTMLElement {
width:70px; text-align:center; font-family:monospace; width:70px; text-align:center; font-family:monospace;
font-size:13px; padding:6px 8px; letter-spacing:1px; font-size:13px; padding:6px 8px; letter-spacing:1px;
} }
.hours-inputs span { color:#6c7a89; font-size:12px; } .hours-inputs span { color:var(--text-muted); font-size:12px; }
.hours-inputs.disabled input { opacity:0.4; pointer-events:none; } .hours-inputs.disabled input { opacity:0.4; pointer-events:none; }
.actions { display:flex; gap:12px; margin-top:24px; } .actions { display:flex; gap:12px; margin-top:24px; }
.loading { text-align:center; padding:60px; color:#8aa0b5; } .loading { text-align:center; padding:60px; color:var(--text-muted); }
.success-msg { .success-msg {
background:#2ecc7130; border:1px solid #2ecc71; background:var(--ok)30; border:1px solid var(--ok);
color:#2ecc71; padding:12px 16px; border-radius:8px; color:var(--ok); padding:12px 16px; border-radius:8px;
margin-bottom:16px; font-size:14px; margin-bottom:16px; font-size:14px;
} }
.error-msg { .error-msg {
background:#e74c3c30; border:1px solid #e74c3c; background:var(--err)30; border:1px solid var(--err);
color:#e74c3c; padding:12px 16px; border-radius:8px; color:var(--err); padding:12px 16px; border-radius:8px;
margin-bottom:16px; font-size:14px; margin-bottom:16px; font-size:14px;
} }
.min-order-field { margin-top:16px; padding-top:16px; border-top:1px solid #1e2a3a; } .min-order-field { margin-top:16px; padding-top:16px; border-top:1px solid var(--border); }
/* Zonas de entrega */ /* Zonas de entrega */
.zones-search { margin-bottom:12px; } .zones-search { margin-bottom:12px; }
.zones-search input { .zones-search input {
width:100%; padding:10px 14px; width:100%; padding:10px 14px;
background:#0f1520 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%236c7a89'%3E%3Cpath d='M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z'/%3E%3C/svg%3E") no-repeat 12px center; background:var(--panel-2) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%236c7a89'%3E%3Cpath d='M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z'/%3E%3C/svg%3E") no-repeat 12px center;
background-size:18px; padding-left:38px; background-size:18px; padding-left:38px;
} }
.zones-list { max-height:400px; overflow-y:auto; display:flex; flex-direction:column; gap:4px; } .zones-list { max-height:400px; overflow-y:auto; display:flex; flex-direction:column; gap:4px; }
@@ -142,18 +142,18 @@ class SettingsCrud extends HTMLElement {
gap:12px; gap:12px;
align-items:start; align-items:start;
padding:10px 12px; padding:10px 12px;
background:#0f1520; background:var(--panel-2);
border-radius:8px; border-radius:8px;
border:1px solid #1e2a3a; border:1px solid var(--border);
transition:border-color .2s; transition:border-color .2s;
} }
.zone-row.active { border-color:#1f6feb; background:#0f1825; } .zone-row.active { border-color:var(--accent); background:var(--accent-soft); }
.zone-row.hidden { display:none; } .zone-row.hidden { display:none; }
.zone-toggle { .zone-toggle {
width:32px; height:18px; background:#253245; border-radius:9px; width:32px; height:18px; background:var(--border-hi); border-radius:9px;
cursor:pointer; position:relative; transition:background .2s; margin-top:2px; cursor:pointer; position:relative; transition:background .2s; margin-top:2px;
} }
.zone-toggle.active { background:#2ecc71; } .zone-toggle.active { background:var(--ok); }
.zone-toggle::after { .zone-toggle::after {
content:''; position:absolute; top:2px; left:2px; content:''; position:absolute; top:2px; left:2px;
width:14px; height:14px; background:#fff; border-radius:50%; width:14px; height:14px; background:#fff; border-radius:50%;
@@ -161,28 +161,28 @@ class SettingsCrud extends HTMLElement {
} }
.zone-toggle.active::after { transform:translateX(14px); } .zone-toggle.active::after { transform:translateX(14px); }
.zone-content { display:flex; flex-direction:column; gap:8px; } .zone-content { display:flex; flex-direction:column; gap:8px; }
.zone-name { font-size:14px; color:#e7eef7; font-weight:500; } .zone-name { font-size:14px; color:var(--text); font-weight:500; }
.zone-config { display:none; gap:16px; flex-wrap:wrap; align-items:center; } .zone-config { display:none; gap:16px; flex-wrap:wrap; align-items:center; }
.zone-row.active .zone-config { display:flex; } .zone-row.active .zone-config { display:flex; }
.zone-days { display:flex; gap:4px; } .zone-days { display:flex; gap:4px; }
.zone-day { .zone-day {
width:28px; height:28px; border-radius:6px; width:28px; height:28px; border-radius:6px;
background:#253245; color:#8aa0b5; background:var(--border-hi); color:var(--text-muted);
display:flex; align-items:center; justify-content:center; display:flex; align-items:center; justify-content:center;
font-size:11px; font-weight:600; cursor:pointer; font-size:11px; font-weight:600; cursor:pointer;
transition:all .15s; transition:all .15s;
} }
.zone-day.active { background:#1f6feb; color:#fff; } .zone-day.active { background:var(--accent); color:#fff; }
.zone-day:hover { background:#2d3e52; } .zone-day:hover { background:var(--border-hi); }
.zone-day.active:hover { background:#1a5fd0; } .zone-day.active:hover { background:var(--accent-hover); }
.zone-cost { display:flex; align-items:center; gap:6px; } .zone-cost { display:flex; align-items:center; gap:6px; }
.zone-cost label { font-size:12px; color:#8aa0b5; } .zone-cost label { font-size:12px; color:var(--text-muted); }
.zone-cost input { width:90px; padding:6px 10px; font-size:13px; text-align:right; } .zone-cost input { width:90px; padding:6px 10px; font-size:13px; text-align:right; }
.zones-summary { .zones-summary {
margin-top:12px; padding:12px; background:#0f1520; margin-top:12px; padding:12px; background:var(--panel-2);
border-radius:8px; font-size:13px; color:#8aa0b5; border-radius:8px; font-size:13px; color:var(--text-muted);
} }
.zones-summary strong { color:#e7eef7; } .zones-summary strong { color:var(--text); }
</style> </style>
<div class="container"> <div class="container">

View File

@@ -18,87 +18,87 @@ class TakeoversCrud extends HTMLElement {
:host { display:block; height:100%; padding:16px; overflow:hidden; } :host { display:block; height:100%; padding:16px; overflow:hidden; }
* { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; } * { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; }
.container { display:grid; grid-template-columns:350px 1fr; gap:16px; height:100%; } .container { display:grid; grid-template-columns:350px 1fr; gap:16px; height:100%; }
.panel { background:#121823; border:1px solid #1e2a3a; border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; } .panel { background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; }
.panel-title { font-size:14px; font-weight:700; color:#8aa0b5; text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; display:flex; align-items:center; gap:8px; } .panel-title { font-size:14px; font-weight:700; color:var(--text-muted); text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; display:flex; align-items:center; gap:8px; }
.panel-title .badge { background:#e74c3c; color:#fff; padding:2px 8px; border-radius:10px; font-size:11px; } .panel-title .badge { background:var(--err); color:#fff; padding:2px 8px; border-radius:10px; font-size:11px; }
input, select, textarea { background:#0f1520; color:#e7eef7; border:1px solid #253245; border-radius:8px; padding:8px 12px; font-size:13px; width:100%; } input, select, textarea { background:var(--panel-2); color:var(--text); border:1px solid var(--border-hi); border-radius:8px; padding:8px 12px; font-size:13px; width:100%; }
input:focus, select:focus, textarea:focus { outline:none; border-color:#1f6feb; } input:focus, select:focus, textarea:focus { outline:none; border-color:var(--accent); }
textarea { resize:vertical; min-height:100px; } textarea { resize:vertical; min-height:100px; }
button { cursor:pointer; background:#1f6feb; color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; } button { cursor:pointer; background:var(--accent); color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; }
button:hover { background:#1a5fd0; } button:hover { background:var(--accent-hover); }
button:disabled { opacity:.5; cursor:not-allowed; } button:disabled { opacity:.5; cursor:not-allowed; }
button.secondary { background:#253245; } button.secondary { background:var(--border-hi); }
button.secondary:hover { background:#2d3e52; } button.secondary:hover { background:var(--border-hi); }
button.danger { background:#e74c3c; } button.danger { background:var(--err); }
button.danger:hover { background:#c0392b; } button.danger:hover { background:var(--err); }
.list { flex:1; overflow-y:auto; } .list { flex:1; overflow-y:auto; }
.item { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; } .item { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; }
.item:hover { border-color:#1f6feb; } .item:hover { border-color:var(--accent); }
.item.active { border-color:#1f6feb; background:#111b2a; } .item.active { border-color:var(--accent); background:var(--accent-soft); }
.item-query { font-weight:600; color:#f39c12; margin-bottom:4px; font-size:14px; } .item-query { font-weight:600; color:var(--warn); margin-bottom:4px; font-size:14px; }
.item-reason { font-size:12px; color:#8aa0b5; margin-bottom:4px; } .item-reason { font-size:12px; color:var(--text-muted); margin-bottom:4px; }
.item-time { font-size:11px; color:#6c7a89; } .item-time { font-size:11px; color:var(--text-muted); }
.item-chat { font-size:11px; color:#1f6feb; } .item-chat { font-size:11px; color:var(--accent); }
.form { flex:1; overflow-y:auto; display:flex; flex-direction:column; gap:16px; } .form { flex:1; overflow-y:auto; display:flex; flex-direction:column; gap:16px; }
.form-empty { color:#8aa0b5; text-align:center; padding:40px; } .form-empty { color:var(--text-muted); text-align:center; padding:40px; }
.field { } .field { }
.field label { display:block; font-size:12px; color:#8aa0b5; margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; } .field label { display:block; font-size:12px; color:var(--text-muted); margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; }
.actions { display:flex; gap:8px; margin-top:16px; } .actions { display:flex; gap:8px; margin-top:16px; }
.loading { text-align:center; padding:40px; color:#8aa0b5; } .loading { text-align:center; padding:40px; color:var(--text-muted); }
.conversation-history { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:12px; max-height:200px; overflow-y:auto; } .conversation-history { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:12px; max-height:200px; overflow-y:auto; }
.msg { margin-bottom:8px; padding:8px; border-radius:6px; font-size:12px; } .msg { margin-bottom:8px; padding:8px; border-radius:6px; font-size:12px; }
.msg.user { background:#1a2a3a; border-left:3px solid #1f6feb; } .msg.user { background:var(--accent-soft); border-left:3px solid var(--accent); }
.msg.assistant { background:#1a2535; border-left:3px solid #2ecc71; } .msg.assistant { background:var(--panel-2); border-left:3px solid var(--ok); }
.msg-role { font-size:10px; color:#8aa0b5; margin-bottom:4px; text-transform:uppercase; } .msg-role { font-size:10px; color:var(--text-muted); margin-bottom:4px; text-transform:uppercase; }
.msg-content { color:#e7eef7; white-space:pre-wrap; } .msg-content { color:var(--text); white-space:pre-wrap; }
.query-highlight { background:#f39c1230; border:1px solid #f39c12; border-radius:8px; padding:12px; margin-bottom:16px; } .query-highlight { background:var(--warn)30; border:1px solid var(--warn); border-radius:8px; padding:12px; margin-bottom:16px; }
.query-highlight label { color:#f39c12; } .query-highlight label { color:var(--warn); }
.query-highlight .query { font-size:16px; font-weight:600; color:#f39c12; margin-top:4px; } .query-highlight .query { font-size:16px; font-weight:600; color:var(--warn); margin-top:4px; }
.alias-section { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:12px; margin-top:12px; } .alias-section { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:12px; margin-top:12px; }
.alias-section h4 { margin:0 0 12px; font-size:13px; color:#8aa0b5; } .alias-section h4 { margin:0 0 12px; font-size:13px; color:var(--text-muted); }
.checkbox-row { display:flex; align-items:center; gap:8px; margin-bottom:12px; } .checkbox-row { display:flex; align-items:center; gap:8px; margin-bottom:12px; }
.checkbox-row input[type="checkbox"] { width:auto; } .checkbox-row input[type="checkbox"] { width:auto; }
.checkbox-row label { font-size:13px; color:#e7eef7; text-transform:none; } .checkbox-row label { font-size:13px; color:var(--text); text-transform:none; }
.product-selector { position:relative; } .product-selector { position:relative; }
.product-dropdown { .product-dropdown {
position:absolute; top:100%; left:0; right:0; z-index:100; position:absolute; top:100%; left:0; right:0; z-index:100;
background:#0f1520; border:1px solid #253245; border-radius:8px; background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px;
max-height:200px; overflow-y:auto; display:none; max-height:200px; overflow-y:auto; display:none;
} }
.product-dropdown.open { display:block; } .product-dropdown.open { display:block; }
.product-option { .product-option {
padding:8px 12px; cursor:pointer; font-size:13px; color:#e7eef7; padding:8px 12px; cursor:pointer; font-size:13px; color:var(--text);
display:flex; justify-content:space-between; align-items:center; display:flex; justify-content:space-between; align-items:center;
} }
.product-option:hover { background:#1a2535; } .product-option:hover { background:var(--panel-2); }
.product-option .price { font-size:11px; color:#8aa0b5; } .product-option .price { font-size:11px; color:var(--text-muted); }
.cart-section { background:#0d2818; border:1px solid #2ecc71; border-radius:8px; padding:12px; margin-bottom:12px; } .cart-section { background:var(--ok-soft); border:1px solid var(--ok); border-radius:8px; padding:12px; margin-bottom:12px; }
.cart-section h4 { margin:0 0 12px; font-size:13px; color:#2ecc71; display:flex; align-items:center; gap:8px; } .cart-section h4 { margin:0 0 12px; font-size:13px; color:var(--ok); display:flex; align-items:center; gap:8px; }
.cart-section h4 svg { width:16px; height:16px; fill:#2ecc71; } .cart-section h4 svg { width:16px; height:16px; fill:var(--ok); }
.cart-items-list { margin-bottom:12px; } .cart-items-list { margin-bottom:12px; }
.cart-item-row { display:flex; align-items:center; gap:8px; padding:8px; background:#0f1520; border-radius:6px; margin-bottom:6px; } .cart-item-row { display:flex; align-items:center; gap:8px; padding:8px; background:var(--panel-2); border-radius:6px; margin-bottom:6px; }
.cart-item-row .name { flex:1; font-size:13px; color:#e7eef7; } .cart-item-row .name { flex:1; font-size:13px; color:var(--text); }
.cart-item-row .qty { width:60px; text-align:center; } .cart-item-row .qty { width:60px; text-align:center; }
.cart-item-row .unit-select { width:80px; } .cart-item-row .unit-select { width:80px; }
.cart-item-row .remove-btn { background:#e74c3c; color:#fff; border:none; border-radius:4px; padding:4px 8px; cursor:pointer; font-size:11px; } .cart-item-row .remove-btn { background:var(--err); color:#fff; border:none; border-radius:4px; padding:4px 8px; cursor:pointer; font-size:11px; }
.cart-item-row .remove-btn:hover { background:#c0392b; } .cart-item-row .remove-btn:hover { background:var(--err); }
.add-cart-row { display:flex; gap:8px; align-items:flex-end; } .add-cart-row { display:flex; gap:8px; align-items:flex-end; }
.add-cart-row .product-selector { flex:1; } .add-cart-row .product-selector { flex:1; }
.add-cart-row .qty-input { width:70px; } .add-cart-row .qty-input { width:70px; }
.add-cart-row .unit-select { width:80px; } .add-cart-row .unit-select { width:80px; }
.add-cart-row button { white-space:nowrap; } .add-cart-row button { white-space:nowrap; }
.no-pending { text-align:center; padding:60px 20px; color:#2ecc71; } .no-pending { text-align:center; padding:60px 20px; color:var(--ok); }
.no-pending svg { width:48px; height:48px; fill:#2ecc71; margin-bottom:16px; } .no-pending svg { width:48px; height:48px; fill:var(--ok); margin-bottom:16px; }
</style> </style>
<div class="container"> <div class="container">
@@ -349,7 +349,7 @@ class TakeoversCrud extends HTMLElement {
if (!container) return; if (!container) return;
if (this.cartItemsToAdd.length === 0) { if (this.cartItemsToAdd.length === 0) {
container.innerHTML = `<div style="font-size:12px;color:#8aa0b5;padding:8px;">Sin items agregados</div>`; container.innerHTML = `<div style="font-size:12px;color:var(--text-muted);padding:8px;">Sin items agregados</div>`;
return; return;
} }

View File

@@ -51,16 +51,13 @@ class TestPanel extends HTMLElement {
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<style> <style>
:host { :host {
--bg: #0b0f14; /* Aliases locales que apuntan a las globals del theme */
--panel: #121823; --line: var(--border);
--muted: #8aa0b5; --blue: var(--accent);
--text: #e7eef7; --green: var(--ok);
--line: #1e2a3a; --red: var(--err);
--blue: #1f6feb;
--green: #238636;
--red: #da3633;
} }
* { box-sizing: border-box; font-family: system-ui, Segoe UI, Roboto, Arial; } * { box-sizing: border-box; font-family: var(--font-sans); }
.container { .container {
height: 100%; height: 100%;
background: var(--bg); background: var(--bg);

View File

@@ -18,45 +18,45 @@ class UsersCrud extends HTMLElement {
:host { display:block; height:100%; padding:16px; overflow:hidden; } :host { display:block; height:100%; padding:16px; overflow:hidden; }
* { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; } * { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; }
.container { display:grid; grid-template-columns:1fr 1fr; gap:16px; height:100%; } .container { display:grid; grid-template-columns:1fr 1fr; gap:16px; height:100%; }
.panel { background:#121823; border:1px solid #1e2a3a; border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; } .panel { background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:16px; overflow:hidden; display:flex; flex-direction:column; }
.panel-title { font-size:14px; font-weight:700; color:#8aa0b5; text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; } .panel-title { font-size:14px; font-weight:700; color:var(--text-muted); text-transform:uppercase; letter-spacing:.4px; margin-bottom:12px; }
.toolbar { display:flex; gap:8px; margin-bottom:12px; } .toolbar { display:flex; gap:8px; margin-bottom:12px; }
input, select { background:#0f1520; color:#e7eef7; border:1px solid #253245; border-radius:8px; padding:8px 12px; font-size:13px; } input, select { background:var(--panel-2); color:var(--text); border:1px solid var(--border-hi); border-radius:8px; padding:8px 12px; font-size:13px; }
input:focus, select:focus { outline:none; border-color:#1f6feb; } input:focus, select:focus { outline:none; border-color:var(--accent); }
input { flex:1; } input { flex:1; }
button { cursor:pointer; background:#1f6feb; color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; } button { cursor:pointer; background:var(--accent); color:#fff; border:none; border-radius:8px; padding:8px 16px; font-size:13px; }
button:hover { background:#1a5fd0; } button:hover { background:var(--accent-hover); }
button:disabled { opacity:.5; cursor:not-allowed; } button:disabled { opacity:.5; cursor:not-allowed; }
button.secondary { background:#253245; } button.secondary { background:var(--border-hi); }
button.secondary:hover { background:#2d3e52; } button.secondary:hover { background:var(--border-hi); }
button.danger { background:#e74c3c; } button.danger { background:var(--err); }
button.danger:hover { background:#c0392b; } button.danger:hover { background:var(--err); }
.list { flex:1; overflow-y:auto; } .list { flex:1; overflow-y:auto; }
.item { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; } .item { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:12px; margin-bottom:8px; cursor:pointer; transition:all .15s; }
.item:hover { border-color:#1f6feb; } .item:hover { border-color:var(--accent); }
.item.active { border-color:#1f6feb; background:#111b2a; } .item.active { border-color:var(--accent); background:var(--accent-soft); }
.item-name { font-weight:600; color:#e7eef7; margin-bottom:4px; } .item-name { font-weight:600; color:var(--text); margin-bottom:4px; }
.item-meta { font-size:12px; color:#8aa0b5; } .item-meta { font-size:12px; color:var(--text-muted); }
.badge { display:inline-block; padding:2px 8px; border-radius:999px; font-size:11px; background:#253245; color:#8aa0b5; margin-left:8px; } .badge { display:inline-block; padding:2px 8px; border-radius:999px; font-size:11px; background:var(--border-hi); color:var(--text-muted); margin-left:8px; }
.badge.woo { background:#0f2a1a; color:#2ecc71; } .badge.woo { background:var(--ok-soft); color:var(--ok); }
.detail { flex:1; overflow-y:auto; } .detail { flex:1; overflow-y:auto; }
.detail-empty { color:#8aa0b5; text-align:center; padding:40px; } .detail-empty { color:var(--text-muted); text-align:center; padding:40px; }
.field { margin-bottom:16px; } .field { margin-bottom:16px; }
.field label { display:block; font-size:12px; color:#8aa0b5; margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; } .field label { display:block; font-size:12px; color:var(--text-muted); margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; }
.field-value { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:10px 12px; color:#e7eef7; font-size:13px; } .field-value { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:10px 12px; color:var(--text); font-size:13px; }
.actions { display:flex; gap:8px; margin-top:16px; flex-wrap:wrap; } .actions { display:flex; gap:8px; margin-top:16px; flex-wrap:wrap; }
.loading { text-align:center; padding:40px; color:#8aa0b5; } .loading { text-align:center; padding:40px; color:var(--text-muted); }
.stats { display:flex; gap:16px; margin-bottom:16px; } .stats { display:flex; gap:16px; margin-bottom:16px; }
.stat { background:#0f1520; border:1px solid #253245; border-radius:8px; padding:12px; flex:1; text-align:center; cursor:pointer; transition:all .15s; } .stat { background:var(--panel-2); border:1px solid var(--border-hi); border-radius:8px; padding:12px; flex:1; text-align:center; cursor:pointer; transition:all .15s; }
.stat:hover { border-color:#1f6feb; } .stat:hover { border-color:var(--accent); }
.stat.active { border-color:#1f6feb; background:#111b2a; } .stat.active { border-color:var(--accent); background:var(--accent-soft); }
.stat-value { font-size:24px; font-weight:700; color:#1f6feb; } .stat-value { font-size:24px; font-weight:700; color:var(--accent); }
.stat-label { font-size:11px; color:#8aa0b5; text-transform:uppercase; margin-top:4px; } .stat-label { font-size:11px; color:var(--text-muted); text-transform:uppercase; margin-top:4px; }
</style> </style>
<div class="container"> <div class="container">

View File

@@ -11,114 +11,81 @@
const STYLES = ` const STYLES = `
.modal-overlay { .modal-overlay {
position: fixed; position: fixed; top: 0; left: 0; right: 0; bottom: 0;
top: 0; background: rgba(15, 23, 42, 0.45);
left: 0; backdrop-filter: blur(2px);
right: 0; display: flex; align-items: center; justify-content: center;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000; z-index: 10000;
animation: fadeIn 0.15s ease-out; animation: fadeIn 0.15s ease-out;
font-family: var(--font-sans, system-ui);
} }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideIn { @keyframes slideIn {
from { transform: translateY(-20px); opacity: 0; } from { transform: translateY(-12px); opacity: 0; }
to { transform: translateY(0); opacity: 1; } to { transform: translateY(0); opacity: 1; }
} }
.modal-box { .modal-box {
background: #1e1e1e; background: var(--panel, #ffffff);
border-radius: 8px; border-radius: var(--r-lg, 12px);
padding: 24px; padding: 24px;
min-width: 320px; min-width: 320px;
max-width: 480px; max-width: 480px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); box-shadow: var(--shadow-lg, 0 12px 28px rgba(15,23,42,.10));
border: 1px solid var(--border, #e2e8f0);
animation: slideIn 0.2s ease-out; animation: slideIn 0.2s ease-out;
border: 1px solid #333;
} }
.modal-header { .modal-header {
display: flex; display: flex; align-items: center; gap: 12px;
align-items: center; margin-bottom: 14px;
gap: 12px;
margin-bottom: 16px;
} }
.modal-icon { .modal-icon {
width: 28px; width: 32px; height: 32px; border-radius: 50%;
height: 28px; display: flex; align-items: center; justify-content: center;
border-radius: 50%; font-size: 16px; font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
flex-shrink: 0; flex-shrink: 0;
} }
.modal-icon.success { background: var(--ok-soft, #d1fae5); color: var(--ok, #10b981); }
.modal-icon.success { background: #22c55e20; color: #22c55e; } .modal-icon.error { background: var(--err-soft, #fee2e2); color: var(--err, #ef4444); }
.modal-icon.error { background: #ef444420; color: #ef4444; } .modal-icon.warn { background: var(--warn-soft, #fef3c7); color: var(--warn, #f59e0b); }
.modal-icon.warn { background: #f59e0b20; color: #f59e0b; } .modal-icon.info { background: var(--accent-soft, #e0f2fe); color: var(--accent, #0ea5e9); }
.modal-icon.info { background: #3b82f620; color: #3b82f6; } .modal-icon.confirm { background: var(--accent-soft, #e0f2fe); color: var(--accent-hover, #0284c7); }
.modal-icon.confirm { background: #8b5cf620; color: #8b5cf6; }
.modal-title { .modal-title {
font-size: 16px; font-size: 16px; font-weight: 600;
font-weight: 600; color: var(--text, #0f172a);
color: #fff;
margin: 0; margin: 0;
letter-spacing: -0.01em;
} }
.modal-message { .modal-message {
color: #ccc; color: var(--text-dim, #475569);
font-size: 14px; font-size: 14px; line-height: 1.5;
line-height: 1.5;
margin-bottom: 20px; margin-bottom: 20px;
word-break: break-word; word-break: break-word;
} }
.modal-buttons { .modal-buttons {
display: flex; display: flex; gap: 8px; justify-content: flex-end;
gap: 12px;
justify-content: flex-end;
} }
.modal-btn { .modal-btn {
padding: 8px 16px; padding: 8px 16px;
border-radius: 6px; border-radius: var(--r-md, 10px);
font-size: 14px; font-size: 13px; font-weight: 500;
font-weight: 500; cursor: pointer; border: 1px solid transparent;
cursor: pointer;
border: none;
transition: all 0.15s; transition: all 0.15s;
font-family: inherit;
} }
.modal-btn:focus-visible { outline: none; box-shadow: var(--focus-ring, 0 0 0 3px rgba(14,165,233,.3)); }
.modal-btn:hover {
filter: brightness(1.1);
}
.modal-btn.primary { .modal-btn.primary {
background: #3b82f6; background: var(--accent, #0ea5e9); color: var(--text-on-acc, #fff);
color: white;
} }
.modal-btn.primary:hover { background: var(--accent-hover, #0284c7); }
.modal-btn.secondary { .modal-btn.secondary {
background: #333; background: var(--panel, #fff); color: var(--text, #0f172a);
color: #ccc; border-color: var(--border-hi, #cbd5e1);
border: 1px solid #444;
} }
.modal-btn.secondary:hover { border-color: var(--accent, #0ea5e9); color: var(--accent-hover, #0284c7); }
.modal-btn.danger { .modal-btn.danger {
background: #ef4444; background: var(--err, #ef4444); color: #fff;
color: white;
} }
.modal-btn.danger:hover { filter: brightness(0.95); }
`; `;
// Inyectar estilos una sola vez // Inyectar estilos una sola vez

View File

@@ -8,12 +8,23 @@
* toast({ kind: "ok", text: "Listo", ms: 2000 }); * toast({ kind: "ok", text: "Listo", ms: 2000 });
*/ */
const KIND_COLORS = { // Lee var del :root con fallback. Permite que la paleta de toasts se adapte
error: { bg: "#241214", border: "#e74c3c", text: "#ffe9ea" }, // al tema sin que el archivo conozca los hex.
ok: { bg: "#0f2a1a", border: "#1f6f43", text: "#cdebd8" }, function v(name, fallback) {
warn: { bg: "#2a1f0a", border: "#F59E0B", text: "#ffe6b0" }, try {
info: { bg: "#0f2030", border: "#1f6feb", text: "#cce0ff" }, 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; let _container = null;
@@ -38,16 +49,19 @@ function ensureContainer() {
export function toast({ kind = "error", text = "", ms = 4000 } = {}) { export function toast({ kind = "error", text = "", ms = 4000 } = {}) {
if (!text) return; if (!text) return;
const colors = KIND_COLORS[kind] || KIND_COLORS.info; const COLORS = kindColors();
const colors = COLORS[kind] || COLORS.info;
const el = document.createElement("div"); const el = document.createElement("div");
Object.assign(el.style, { Object.assign(el.style, {
background: colors.bg, background: colors.bg,
border: `1px solid ${colors.border}`, border: `1px solid ${colors.border}`,
color: colors.text, color: colors.text,
padding: "10px 12px", padding: "12px 16px",
borderRadius: "10px", borderRadius: "12px",
fontSize: "13px", fontSize: "13px",
boxShadow: "0 4px 12px rgba(0,0,0,.4)", fontWeight: "500",
fontFamily: "var(--font-sans, system-ui)",
boxShadow: "var(--shadow-md, 0 4px 12px rgba(15,23,42,.06))",
pointerEvents: "auto", pointerEvents: "auto",
cursor: "pointer", cursor: "pointer",
transform: "translateX(120%)", transform: "translateX(120%)",

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -1,74 +1,156 @@
/** /**
* Tema global (CSS custom properties). * Tema global Botino — light pastel frío (azul/verde).
* *
* Las custom properties heredan a través del shadow DOM, así que cualquier * CSS custom properties heredan a través del shadow DOM, así que cualquier
* componente puede usar `var(--bg)` sin re-declarar nada. * componente puede usar `var(--bg)` sin re-declarar nada.
*/ */
/* ────────────────────────────────────────────────────────────
* Tipografía: Inter + JetBrains Mono (variable, self-hosted)
* ──────────────────────────────────────────────────────────── */
@font-face {
font-family: "Inter";
src: url("/styles/fonts/Inter-Variable.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "JetBrains Mono";
src: url("/styles/fonts/JetBrainsMono-Variable.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
/* ────────────────────────────────────────────────────────────
* Tokens de diseño
* ──────────────────────────────────────────────────────────── */
:root { :root {
/* Surfaces */ /* Surfaces */
--bg: #0b0f14; --bg: #f7fafc; /* casi blanco con tinte azul muy sutil */
--panel: #121823; --panel: #ffffff; /* tarjetas / paneles principales */
--panel-2: #0f1520; --panel-2: #f1f5f9; /* slate-100 */
--panel-3: #0a0e15; --panel-3: #e2e8f0; /* slate-200 */
/* Borders */ /* Borders */
--border: #1e2a3a; --border: #e2e8f0; /* slate-200 */
--border-hi: #253245; --border-hi: #cbd5e1; /* slate-300 */
--border-active:#1f6feb; --border-active:#0ea5e9; /* sky-500 */
/* Text */ /* Text */
--text: #e7eef7; --text: #0f172a; /* slate-900 */
--text-muted: #8aa0b5; --text-dim: #475569; /* slate-600 */
--text-dim: #d7e2ef; --text-muted: #64748b; /* slate-500 */
--text-on-acc: #ffffff; --text-on-acc: #ffffff;
/* Accents */
--accent: #1f6feb;
--accent-hover: #2570f0;
--ok: #25D366;
--warn: #F59E0B;
--err: #e74c3c;
/* Bubbles */
--user-bubble: #0f2a1a;
--user-border: #1f6f43;
--user-meta: #b9d9c6;
--user-name: #cdebd8;
--bot-bubble: #111b2a;
--bot-border: #2a3a55;
--bot-meta: #a9bed6;
--bot-name: #c7d8ee;
--err-bubble: #241214;
--err-border: #e74c3c;
--err-meta: #ffd0d4;
--err-name: #ffd0d4;
/* Charts (alias para componentes que aún usan literales) */
--chart-blue: #3b82f6;
--chart-green: #25D366;
--chart-purple: #8B5CF6;
--chart-orange: #F59E0B;
--chart-pink: #EC4899;
--chart-gray: #9CA3AF;
/* Radii / shadows */
--r-sm: 6px;
--r-md: 8px;
--r-lg: 10px;
--r-xl: 14px;
--shadow-bubble: 0 1px 0 rgba(0,0,0,.35);
}
/* Compat: alias antiguo `--muted` que ya usa ops-shell.js. */
:root {
--muted: var(--text-muted); --muted: var(--text-muted);
/* Accents — azul/verde fríos como protagonistas */
--accent: #0ea5e9; /* sky-500 */
--accent-hover: #0284c7; /* sky-600 */
--accent-soft: #e0f2fe; /* sky-100 */
--ok: #10b981; /* emerald-500 */
--ok-soft: #d1fae5; /* emerald-100 */
--warn: #f59e0b; /* amber-500 */
--warn-soft: #fef3c7;
--err: #ef4444; /* red-500 */
--err-soft: #fee2e2;
/* Bubbles — light pastel */
--user-bubble: #d1fae5; /* emerald-100 (cliente) */
--user-border: #6ee7b7; /* emerald-300 */
--user-text: #064e3b; /* emerald-900 */
--user-name: #047857; /* emerald-700 */
--user-meta: #059669; /* emerald-600 */
--bot-bubble: #dbeafe; /* blue-100 (bot) */
--bot-border: #93c5fd; /* blue-300 */
--bot-text: #1e3a8a; /* blue-900 */
--bot-name: #1d4ed8; /* blue-700 */
--bot-meta: #2563eb; /* blue-600 */
--err-bubble: #fee2e2;
--err-border: #fca5a5;
--err-text: #7f1d1d;
--err-name: #b91c1c;
--err-meta: #dc2626;
/* Charts — paleta pastel coordinada (~400 saturación) */
--chart-blue: #38bdf8; /* sky-400 */
--chart-green: #34d399; /* emerald-400 */
--chart-purple: #a78bfa; /* violet-400 */
--chart-orange: #fb923c; /* orange-400 */
--chart-pink: #f472b6; /* pink-400 */
--chart-gray: #94a3b8; /* slate-400 */
--chart-blue-soft: rgba(56, 189, 248, 0.20);
--chart-green-soft: rgba(52, 211, 153, 0.20);
/* Spacing scale */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 20px;
--space-6: 24px;
--space-8: 32px;
/* Radii */
--r-sm: 8px;
--r-md: 10px;
--r-lg: 12px;
--r-xl: 16px;
/* Shadows */
--shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.04);
--shadow-md: 0 4px 12px rgba(15, 23, 42, 0.06);
--shadow-lg: 0 12px 28px rgba(15, 23, 42, 0.10);
--shadow-bubble: 0 1px 2px rgba(15, 23, 42, 0.04);
/* Type scale */
--font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, "Fira Mono", monospace;
--fs-xs: 11px;
--fs-sm: 12px;
--fs-base: 14px;
--fs-md: 15px;
--fs-lg: 18px;
--fs-xl: 24px;
--fw-regular: 400;
--fw-medium: 500;
--fw-semibold: 600;
--fw-bold: 700;
--lh-base: 1.5;
--lh-tight: 1.3;
/* Focus ring (accesibilidad) */
--focus-ring: 0 0 0 3px var(--accent-soft);
} }
/* ────────────────────────────────────────────────────────────
* Reset / defaults
* ──────────────────────────────────────────────────────────── */
html, body { html, body {
background: var(--bg); background: var(--bg);
color: var(--text); color: var(--text);
margin: 0; margin: 0;
font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif; font-family: var(--font-sans);
font-size: var(--fs-base);
line-height: var(--lh-base);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
} }
* { box-sizing: border-box; }
/* Scrollbars finos / pastel */
* {
scrollbar-width: thin;
scrollbar-color: var(--border-hi) transparent;
}
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-thumb { background: var(--border-hi); border-radius: 4px; }
*::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
*::-webkit-scrollbar-track { background: transparent; }
/* Selection con tinte pastel */
::selection { background: var(--accent-soft); color: var(--text); }