Config: layout más amplio + toolbar sticky con Guardar
Antes: container 800px centrado, 3 panels stacked vertical, save al final.
Ahora:
- Container 1600px max, padding 24px.
- Toolbar sticky arriba con título "Configuración" + Restaurar + Guardar
(reemplaza la sección final).
- Settings grid de 2 columnas (340px / 1fr) que colapsa a 1 col en <960px:
- Izq: panel "Información del Negocio" (campos apilados, más densos) +
panel "Retiro en Tienda" (toggle + grid).
- Der: panel "Zonas de Entrega" full-width — el mapa ocupa la mayor parte
de la pantalla (height:calc(100vh-220px), min 520px).
- zones-layout dentro del panel: 300px lista/form / 1fr mapa flex.
- Sin pérdida funcional: mismos campos, mismas validaciones, mismas tools.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,10 +30,33 @@ class SettingsCrud extends HTMLElement {
|
||||
|
||||
this.shadowRoot.innerHTML = `
|
||||
<style>
|
||||
:host { display:block; height:100%; padding:16px; overflow:auto; }
|
||||
* { box-sizing:border-box; font-family:system-ui,Segoe UI,Roboto,Arial; }
|
||||
.container { max-width:800px; margin:0 auto; }
|
||||
.panel { background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:20px; margin-bottom:16px; }
|
||||
:host { display:block; height:100%; padding:16px 24px 24px; overflow:auto; }
|
||||
* { box-sizing:border-box; font-family:var(--font-sans, system-ui); }
|
||||
.container { max-width:1600px; margin:0 auto; }
|
||||
.settings-grid {
|
||||
display:grid;
|
||||
grid-template-columns:minmax(320px, 360px) minmax(0, 1fr);
|
||||
gap:16px;
|
||||
align-items:start;
|
||||
}
|
||||
@media (max-width: 960px) {
|
||||
.settings-grid { grid-template-columns:1fr; }
|
||||
}
|
||||
.col { display:flex; flex-direction:column; gap:16px; }
|
||||
.panel { background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:20px; }
|
||||
.panel-zones { padding:16px 16px 20px; display:flex; flex-direction:column; min-height:560px; }
|
||||
.toolbar {
|
||||
display:flex; align-items:center; justify-content:space-between;
|
||||
gap:16px; padding:12px 4px 16px;
|
||||
position:sticky; top:0; z-index:5; background:var(--bg, #f7fafc);
|
||||
border-bottom:1px solid var(--border);
|
||||
margin-bottom:16px;
|
||||
}
|
||||
.toolbar-title { margin:0; font-size:18px; font-weight:600; color:var(--text); }
|
||||
.toolbar-actions { display:flex; gap:8px; }
|
||||
.toolbar-actions button { padding:8px 16px; font-size:13px; }
|
||||
.zones-map-wrap { display:flex; min-height:520px; min-width:0; }
|
||||
.zones-map-wrap zone-map-editor { flex:1; height:auto; min-height:520px; }
|
||||
.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:var(--accent); }
|
||||
|
||||
@@ -125,12 +148,13 @@ class SettingsCrud extends HTMLElement {
|
||||
.min-order-field { margin-top:16px; padding-top:16px; border-top:1px solid var(--border); }
|
||||
|
||||
/* Zonas de entrega — editor con mapa */
|
||||
.zones-layout { display:grid; grid-template-columns:280px 1fr; gap:16px; }
|
||||
.zones-side { display:flex; flex-direction:column; gap:8px; min-width:0; }
|
||||
.zones-layout { display:grid; grid-template-columns:300px minmax(0,1fr); gap:16px; height:calc(100vh - 220px); min-height:520px; }
|
||||
@media (max-width: 1100px) { .zones-layout { grid-template-columns:1fr; height:auto; } }
|
||||
.zones-side { display:flex; flex-direction:column; gap:8px; min-width:0; min-height:0; }
|
||||
.zones-side-header { display:flex; align-items:center; justify-content:space-between; }
|
||||
.zones-side-header h4 { margin:0; font-size:13px; color:var(--text); }
|
||||
.zones-side-header button { padding:6px 10px; font-size:12px; }
|
||||
.zones-list { display:flex; flex-direction:column; gap:6px; max-height:480px; overflow-y:auto; padding-right:4px; }
|
||||
.zones-list { display:flex; flex-direction:column; gap:6px; flex:1; min-height:120px; max-height:50%; overflow-y:auto; padding-right:4px; }
|
||||
.zone-row {
|
||||
display:flex; align-items:center; gap:10px;
|
||||
padding:10px 12px; border-radius:var(--r-md, 10px);
|
||||
@@ -376,89 +400,89 @@ class SettingsCrud extends HTMLElement {
|
||||
const s = this.settings;
|
||||
|
||||
content.innerHTML = `
|
||||
<!-- Info del Negocio -->
|
||||
<div class="panel">
|
||||
<div class="panel-title">
|
||||
<svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>
|
||||
Información del Negocio
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="field">
|
||||
<label>Nombre del negocio</label>
|
||||
<input type="text" id="storeName" value="${this.escapeHtml(s.store_name || "")}" placeholder="Ej: Carnicería Don Pedro" />
|
||||
<div class="field-hint">Se usa en los mensajes del bot</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Nombre del bot</label>
|
||||
<input type="text" id="botName" value="${this.escapeHtml(s.bot_name || "")}" placeholder="Ej: Piaf" />
|
||||
<div class="field-hint">El asistente virtual</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="field">
|
||||
<label>Dirección</label>
|
||||
<input type="text" id="storeAddress" value="${this.escapeHtml(s.store_address || "")}" placeholder="Ej: Av. Corrientes 1234, CABA" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Teléfono</label>
|
||||
<input type="text" id="storePhone" value="${this.escapeHtml(s.store_phone || "")}" placeholder="Ej: +54 11 1234-5678" />
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<h2 class="toolbar-title">Configuración</h2>
|
||||
<div class="toolbar-actions">
|
||||
<button id="resetBtn" class="secondary" type="button">Restaurar</button>
|
||||
<button id="saveBtn" type="button" ${this.saving ? "disabled" : ""}>
|
||||
${this.saving ? "Guardando..." : "Guardar"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Retiro en tienda -->
|
||||
<div class="panel">
|
||||
<div class="panel-title">
|
||||
<svg viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 14l-5-5 1.41-1.41L12 14.17l4.59-4.58L18 11l-6 6z"/></svg>
|
||||
Retiro en Tienda
|
||||
</div>
|
||||
|
||||
<div class="toggle-row">
|
||||
<div class="toggle ${s.pickup_enabled ? "active" : ""}" id="pickupToggle"></div>
|
||||
<span class="toggle-label">Retiro en tienda habilitado</span>
|
||||
</div>
|
||||
|
||||
<div class="schedule-grid" id="pickupSchedule">
|
||||
${this.renderScheduleGrid("pickup", s.pickup_enabled)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Zonas de Entrega -->
|
||||
<div class="panel">
|
||||
<div class="panel-title">
|
||||
<svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></svg>
|
||||
Zonas de Entrega
|
||||
</div>
|
||||
<div class="field-hint" style="margin-bottom:12px;">
|
||||
Dibujá los polígonos de tus zonas en el mapa. Cada zona tiene su costo de envío, días y rango horario.
|
||||
El bot valida la dirección del cliente con la ubicación que comparta por WhatsApp.
|
||||
</div>
|
||||
|
||||
<div class="zones-layout">
|
||||
<div class="zones-side">
|
||||
<div class="zones-side-header">
|
||||
<h4>Zonas</h4>
|
||||
<button id="zoneCreateBtn" type="button">+ Crear zona</button>
|
||||
<div class="settings-grid">
|
||||
<div class="col">
|
||||
<div class="panel">
|
||||
<div class="panel-title">
|
||||
<svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>
|
||||
Información del Negocio
|
||||
</div>
|
||||
<div class="zones-list" id="zonesList">
|
||||
${this.renderZonesList()}
|
||||
<div class="field" style="margin-bottom:12px;">
|
||||
<label>Nombre del negocio</label>
|
||||
<input type="text" id="storeName" value="${this.escapeHtml(s.store_name || "")}" placeholder="Ej: Carnicería Don Pedro" />
|
||||
<div class="field-hint">Se usa en los mensajes del bot</div>
|
||||
</div>
|
||||
<div id="zoneFormSlot">
|
||||
${this.renderZoneForm()}
|
||||
<div class="field" style="margin-bottom:12px;">
|
||||
<label>Nombre del bot</label>
|
||||
<input type="text" id="botName" value="${this.escapeHtml(s.bot_name || "")}" placeholder="Ej: Piaf" />
|
||||
<div class="field-hint">El asistente virtual</div>
|
||||
</div>
|
||||
<div class="field" style="margin-bottom:12px;">
|
||||
<label>Dirección</label>
|
||||
<input type="text" id="storeAddress" value="${this.escapeHtml(s.store_address || "")}" placeholder="Av. Corrientes 1234, CABA" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Teléfono</label>
|
||||
<input type="text" id="storePhone" value="${this.escapeHtml(s.store_phone || "")}" placeholder="+54 11 1234-5678" />
|
||||
</div>
|
||||
${this.renderZonesSummary()}
|
||||
</div>
|
||||
<div>
|
||||
<zone-map-editor id="zoneMapEditor" height="520px"></zone-map-editor>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-title">
|
||||
<svg viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 14l-5-5 1.41-1.41L12 14.17l4.59-4.58L18 11l-6 6z"/></svg>
|
||||
Retiro en Tienda
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<div class="toggle ${s.pickup_enabled ? "active" : ""}" id="pickupToggle"></div>
|
||||
<span class="toggle-label">Retiro habilitado</span>
|
||||
</div>
|
||||
<div class="schedule-grid" id="pickupSchedule">
|
||||
${this.renderScheduleGrid("pickup", s.pickup_enabled)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button id="saveBtn" ${this.saving ? "disabled" : ""}>${this.saving ? "Guardando..." : "Guardar Configuración"}</button>
|
||||
<button id="resetBtn" class="secondary">Restaurar</button>
|
||||
<div class="col">
|
||||
<div class="panel panel-zones">
|
||||
<div class="panel-title" style="margin-bottom:6px;">
|
||||
<svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></svg>
|
||||
Zonas de Entrega
|
||||
</div>
|
||||
<div class="field-hint" style="margin-bottom:12px;">
|
||||
Dibujá los polígonos en el mapa. Cada zona tiene su costo, días y rango horario.
|
||||
El bot matchea con la ubicación que el cliente comparta por WhatsApp.
|
||||
</div>
|
||||
|
||||
<div class="zones-layout">
|
||||
<div class="zones-side">
|
||||
<div class="zones-side-header">
|
||||
<h4>Zonas</h4>
|
||||
<button id="zoneCreateBtn" type="button">+ Crear zona</button>
|
||||
</div>
|
||||
<div class="zones-list" id="zonesList">
|
||||
${this.renderZonesList()}
|
||||
</div>
|
||||
<div id="zoneFormSlot">
|
||||
${this.renderZoneForm()}
|
||||
</div>
|
||||
${this.renderZonesSummary()}
|
||||
</div>
|
||||
<div class="zones-map-wrap">
|
||||
<zone-map-editor id="zoneMapEditor"></zone-map-editor>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user