mi-proyecto/app/templates/admin_frontend.html

60 lines
9.4 KiB
HTML

{% extends 'base.html' %}
{% block content %}
<div class="page-toolbar">
<div><h1 class="h3 mb-1">Frontend</h1><p class="text-muted mb-0">Configurá el contenido del template MediLab respetando su estructura visual.</p></div>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#frontendBlockModal"><i class="bi bi-plus-circle"></i> Nuevo bloque</button>
</div>
<div class="row g-4">
<div class="col-lg-4">
<div class="card table-panel h-100"><div class="card-header"><strong>Datos estructurales</strong></div><div class="card-body">
<form method="post" enctype="multipart/form-data" class="row g-3 geo-form">
<input type="hidden" name="action" value="save_core">
<div class="col-12"><label class="form-label">Título del sitio</label><input class="form-control" name="site_title" value="{{ settings.title }}"></div>
<div class="col-md-6"><label class="form-label">Tagline</label><input class="form-control" name="site_tagline" value="{{ settings.tagline }}"></div>
<div class="col-md-6"><label class="form-label">Botón CTA</label><input class="form-control" name="site_nav_cta_label" value="{{ settings.nav_cta_label }}"></div>
<div class="col-md-6"><label class="form-label">Email</label><input class="form-control" name="site_email" value="{{ settings.email }}"></div>
<div class="col-md-6"><label class="form-label">Teléfono</label><input class="form-control" name="site_phone" value="{{ settings.phone }}"></div>
<div class="col-12"><label class="form-label">Dirección / ubicación</label><textarea class="form-control" name="site_contact_address" rows="2">{{ settings.contact_address }}</textarea></div>
<div class="col-12"><label class="form-label">Mapa embebido</label><textarea class="form-control" name="site_contact_map_embed" rows="4" placeholder="Pegá iframe o embed">{{ settings.contact_map_embed }}</textarea></div>
<div class="col-md-6"><label class="form-label">Logo</label><input type="file" class="form-control" name="site_logo" accept="image/*"></div>
<div class="col-md-6"><label class="form-label">Favicon</label><input type="file" class="form-control" name="site_favicon" accept="image/*"></div>
<div class="col-12"><label class="form-label">Copyright</label><input class="form-control" name="site_copyright" value="{{ settings.copyright }}"></div>
{% for network, label in [('facebook','Facebook'),('instagram','Instagram'),('x','X / Twitter'),('youtube','YouTube'),('linkedin','LinkedIn')] %}
<div class="col-md-4 d-flex align-items-end"><div class="form-check"><input class="form-check-input" type="checkbox" name="site_social_{{ network }}_enabled" {% if settings.socials_raw[network].enabled %}checked{% endif %}><label class="form-check-label">{{ label }}</label></div></div>
<div class="col-md-8"><label class="form-label">URL {{ label }}</label><input class="form-control" name="site_social_{{ network }}_url" value="{{ settings.socials_raw[network].url }}"></div>
{% endfor %}
<div class="col-12 d-grid"><button class="btn btn-primary">Guardar estructura</button></div>
</form>
</div></div>
</div>
<div class="col-lg-8">
<div class="card table-panel"><div class="card-header"><strong>Bloques del frontend</strong></div><div class="table-responsive wide-table"><table class="table align-middle mb-0"><thead><tr><th>Sección</th><th>Título</th><th>Resumen</th><th>Orden</th><th class="text-end">Acciones</th></tr></thead><tbody>
{% for section, label in section_labels.items() %}
{% for item in grouped.get(section, []) %}
<tr>
<td><span class="badge text-bg-light">{{ label }}</span></td>
<td>{{ item.title or '—' }}</td>
<td class="text-wrap">{{ item.body or item.subtitle or '—' }}</td>
<td>{{ item.sort_order }}</td>
<td class="text-end"><div class="d-flex gap-2 justify-content-end"><button class="btn btn-sm btn-outline-primary frontend-edit-btn" data-block='{{ {"id": item.id, "section": item.section, "key": item.key, "title": item.title, "subtitle": item.subtitle, "body": item.body, "icon": item.icon, "link_url": item.link_url, "link_text": item.link_text, "sort_order": item.sort_order, "extra_json": item.extra_json, "is_active": item.is_active, "image_path": item.image_path}|tojson|safe }}' data-bs-toggle="modal" data-bs-target="#frontendBlockModal">Editar</button><form method="post" onsubmit="return confirm('¿Eliminar bloque?')"><input type="hidden" name="action" value="delete_block"><input type="hidden" name="block_id" value="{{ item.id }}"><button class="btn btn-sm btn-outline-danger">Eliminar</button></form></div></td>
</tr>
{% endfor %}
{% endfor %}
{% if not grouped.values()|select|list %}<tr><td colspan="5" class="text-center text-muted py-4">No hay bloques configurados todavía.</td></tr>{% endif %}
</tbody></table></div></div>
</div>
</div>
<div class="modal fade" id="frontendBlockModal" tabindex="-1" aria-hidden="true"><div class="modal-dialog modal-xl modal-dialog-scrollable"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Bloque del frontend</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div>
<form method="post" enctype="multipart/form-data" id="frontendBlockForm">
<input type="hidden" name="action" value="save_block"><input type="hidden" name="block_id" id="frontend_block_id">
<div class="modal-body"><div class="row g-4">
<div class="col-lg-4"><div class="section-card h-100"><div class="section-title">Clasificación</div><div class="row g-3"><div class="col-12"><label class="form-label">Sección</label><select class="form-select searchable-select" name="section" id="frontend_section" required>{% for section, label in section_labels.items() %}<option value="{{ section }}">{{ label }}</option>{% endfor %}</select></div><div class="col-12"><label class="form-label">Clave</label><input class="form-control" name="key" id="frontend_key" placeholder="slug interno"></div><div class="col-md-6"><label class="form-label">Orden</label><input class="form-control" name="sort_order" id="frontend_sort_order" value="0"></div><div class="col-md-6 d-flex align-items-end"><div class="form-check"><input class="form-check-input" type="checkbox" name="is_active" id="frontend_is_active" checked><label class="form-check-label">Activo</label></div></div><div class="col-12"><label class="form-label">Ícono</label><input class="form-control" name="icon" id="frontend_icon" placeholder="bi bi-heart-pulse o fa-solid fa-user-doctor"></div><div class="col-12"><label class="form-label">Imagen</label><input type="file" class="form-control" name="image_file"><div class="small text-muted mt-1" id="frontend_image_hint"></div></div></div></div></div>
<div class="col-lg-8"><div class="section-card"><div class="section-title">Contenido</div><div class="row g-3"><div class="col-md-6"><label class="form-label">Título</label><input class="form-control" name="title" id="frontend_title"></div><div class="col-md-6"><label class="form-label">Subtítulo / número</label><input class="form-control" name="subtitle" id="frontend_subtitle"></div><div class="col-12"><label class="form-label">Texto / descripción</label><textarea class="form-control" name="body" id="frontend_body" rows="6"></textarea></div><div class="col-md-6"><label class="form-label">Link URL</label><input class="form-control" name="link_url" id="frontend_link_url"></div><div class="col-md-6"><label class="form-label">Texto del link</label><input class="form-control" name="link_text" id="frontend_link_text"></div><div class="col-12"><label class="form-label">JSON extra</label><textarea class="form-control" name="extra_json" id="frontend_extra_json" rows="4" placeholder='Ej. {"align":"center"}'></textarea></div></div></div></div>
</div></div>
<div class="modal-footer"><button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancelar</button><button class="btn btn-primary">Guardar bloque</button></div>
</form>
</div></div></div>
{% endblock %}
{% block scripts %}{{ super() }}<script>document.addEventListener('DOMContentLoaded',function(){document.querySelectorAll('.frontend-edit-btn').forEach(function(btn){btn.addEventListener('click',function(){const data=JSON.parse(btn.getAttribute('data-block'));document.getElementById('frontend_block_id').value=data.id||'';document.getElementById('frontend_section').value=data.section||'';document.getElementById('frontend_key').value=data.key||'';document.getElementById('frontend_sort_order').value=data.sort_order||0;document.getElementById('frontend_title').value=data.title||'';document.getElementById('frontend_subtitle').value=data.subtitle||'';document.getElementById('frontend_body').value=data.body||'';document.getElementById('frontend_icon').value=data.icon||'';document.getElementById('frontend_link_url').value=data.link_url||'';document.getElementById('frontend_link_text').value=data.link_text||'';document.getElementById('frontend_extra_json').value=data.extra_json||'';document.getElementById('frontend_is_active').checked=!!data.is_active;document.getElementById('frontend_image_hint').textContent=data.image_path?('Actual: '+data.image_path):'';});});document.getElementById('frontendBlockModal').addEventListener('hidden.bs.modal',function(){document.getElementById('frontendBlockForm').reset();document.getElementById('frontend_block_id').value='';document.getElementById('frontend_image_hint').textContent='';});});</script>{% endblock %}