feat: modal pacientes rediseñado — más elegante y moderno
- Header con avatar de iniciales + gradiente brand + subtítulo - Secciones agrupadas en cards con fondo sutil y borde brand - Todos los campos usan form-floating (labels animados) - Footer con botones mejor definidos y gradiente brand - Avatar se actualiza en tiempo real al escribir el nombre Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
8bf3614fa0
commit
86cfad6e68
+196
-107
@@ -58,44 +58,80 @@ $brandDark = sprintf('#%02x%02x%02x',
|
||||
.hist-badge { font-size: .72rem; }
|
||||
#detail-panel { display: none; }
|
||||
|
||||
/* Modal header con gradiente brand */
|
||||
/* ── Modal header ──────────────────────────────── */
|
||||
.modal-header-brand {
|
||||
background: linear-gradient(135deg, var(--brand-dark) 0%, var(--brand) 100%);
|
||||
color: #fff;
|
||||
border-radius: .5rem .5rem 0 0;
|
||||
padding: 1rem 1.25rem;
|
||||
padding: 1.4rem 1.5rem 1rem;
|
||||
position: relative;
|
||||
}
|
||||
.modal-header-brand .modal-title { color: #fff; font-size: .95rem; font-weight: 700; }
|
||||
.modal-header-brand .btn-close { filter: invert(1) brightness(2); }
|
||||
|
||||
/* Secciones del formulario */
|
||||
.form-section-label {
|
||||
font-size: .68rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .1em;
|
||||
color: var(--brand);
|
||||
margin: .75rem 0 .4rem;
|
||||
padding-bottom: .25rem;
|
||||
border-bottom: 1px solid color-mix(in srgb, var(--brand) 20%, transparent);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .4rem;
|
||||
.pac-avatar {
|
||||
width: 52px; height: 52px; border-radius: 50%;
|
||||
background: rgba(255,255,255,.18);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 1.4rem; font-weight: 800; color: #fff;
|
||||
border: 2px solid rgba(255,255,255,.35);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.modal-header-brand .modal-title {
|
||||
color: #fff; font-size: 1rem; font-weight: 700; line-height: 1.2;
|
||||
}
|
||||
.modal-header-brand .modal-subtitle {
|
||||
font-size: .75rem; opacity: .75; margin-top: 1px;
|
||||
}
|
||||
|
||||
/* Panel detalle */
|
||||
/* ── Secciones ─────────────────────────────────── */
|
||||
.form-section {
|
||||
background: #f8faff;
|
||||
border: 1px solid color-mix(in srgb, var(--brand) 12%, #e2e8f0);
|
||||
border-radius: .6rem;
|
||||
padding: .9rem 1rem .6rem;
|
||||
margin-bottom: .8rem;
|
||||
}
|
||||
.form-section-label {
|
||||
font-size: .65rem; font-weight: 800; text-transform: uppercase;
|
||||
letter-spacing: .1em; color: var(--brand);
|
||||
margin: 0 0 .65rem;
|
||||
display: flex; align-items: center; gap: .4rem;
|
||||
}
|
||||
.form-section-label i { opacity: .7; }
|
||||
|
||||
/* Floating label overrides */
|
||||
.form-floating > label { font-size: .8rem; color: #64748b; }
|
||||
.form-floating > .form-control,
|
||||
.form-floating > .form-select { font-size: .875rem; border-color: #dde3ed; border-radius: .45rem; }
|
||||
.form-floating > .form-control:focus,
|
||||
.form-floating > .form-select:focus {
|
||||
border-color: var(--brand);
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 15%, transparent);
|
||||
}
|
||||
|
||||
/* ── Modal footer ──────────────────────────────── */
|
||||
.modal-footer-brand {
|
||||
background: #f8faff;
|
||||
border-top: 1px solid #e8edf5;
|
||||
padding: .8rem 1.25rem;
|
||||
display: flex; gap: .5rem; justify-content: flex-end;
|
||||
}
|
||||
.btn-brand-solid {
|
||||
background: linear-gradient(135deg, var(--brand-dark), var(--brand));
|
||||
color: #fff; border: none; border-radius: .45rem;
|
||||
padding: .45rem 1.2rem; font-size: .85rem; font-weight: 600;
|
||||
transition: opacity .15s;
|
||||
}
|
||||
.btn-brand-solid:hover { opacity: .88; color: #fff; }
|
||||
|
||||
/* ── Panel detalle ─────────────────────────────── */
|
||||
.detail-header-band {
|
||||
background: linear-gradient(135deg, var(--brand-dark) 0%, var(--brand) 100%);
|
||||
color: #fff;
|
||||
border-radius: .5rem .5rem 0 0;
|
||||
color: #fff; border-radius: .5rem .5rem 0 0;
|
||||
padding: .75rem 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
}
|
||||
.detail-header-band .btn-close { filter: invert(1) brightness(2); }
|
||||
|
||||
/* Row hover en tabla */
|
||||
/* ── Tabla ─────────────────────────────────────── */
|
||||
.table-hover tbody tr:hover { background: color-mix(in srgb, var(--brand) 6%, #fff) !important; }
|
||||
</style>
|
||||
</head>
|
||||
@@ -177,104 +213,146 @@ require_once __DIR__ . '/shared/components/sidebar.php';
|
||||
<!-- Modal Formulario Paciente -->
|
||||
<div class="modal fade" id="modalPaciente" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||
<div class="modal-content border-0 shadow rounded-3 overflow-hidden">
|
||||
<div class="modal-header-brand">
|
||||
<h6 class="modal-title" id="modal-titulo"><i class="fas fa-user me-2"></i>Nuevo Paciente</h6>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
<div class="modal-content border-0 shadow-lg rounded-4 overflow-hidden">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="modal-header-brand d-flex align-items-center gap-3">
|
||||
<div class="pac-avatar" id="modal-avatar">?</div>
|
||||
<div class="flex-1">
|
||||
<div class="modal-title" id="modal-titulo">Nuevo Paciente</div>
|
||||
<div class="modal-subtitle" id="modal-subtitulo">Completa los datos del paciente</div>
|
||||
</div>
|
||||
<button type="button" class="btn-close ms-auto" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body py-3 px-4">
|
||||
<form id="form-paciente" autocomplete="off">
|
||||
<input type="hidden" name="id" id="pac-id">
|
||||
|
||||
<!-- Datos personales -->
|
||||
<div class="form-section-label"><i class="fas fa-id-card"></i> Datos personales</div>
|
||||
<div class="row g-2">
|
||||
<div class="col-12">
|
||||
<label class="form-label small fw-semibold mb-1">Nombre completo <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control form-control-sm" name="nombre_completo" id="pac-nombre" required placeholder="Ej: María García López">
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label small fw-semibold mb-1">Tipo doc.</label>
|
||||
<select class="form-select form-select-sm" name="tipo_documento" id="pac-tipo-doc">
|
||||
<option value="CC">CC — Cédula</option>
|
||||
<option value="CE">CE — Extranjería</option>
|
||||
<option value="TI">TI — Tarjeta Identidad</option>
|
||||
<option value="PA">PA — Pasaporte</option>
|
||||
<option value="DE">DE — Doc. Extranjero</option>
|
||||
<option value="NIT">NIT</option>
|
||||
<option value="RC">RC — Reg. Civil</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label small fw-semibold mb-1">Número documento</label>
|
||||
<input type="text" class="form-control form-control-sm" name="numero_documento" id="pac-doc" placeholder="123456789">
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label small fw-semibold mb-1">Fecha nacimiento</label>
|
||||
<input type="date" class="form-control form-control-sm" name="fecha_nacimiento" id="pac-fnac">
|
||||
<div class="form-section">
|
||||
<div class="form-section-label"><i class="fas fa-id-card"></i> Datos personales</div>
|
||||
<div class="row g-2">
|
||||
<div class="col-12">
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control" name="nombre_completo" id="pac-nombre"
|
||||
required placeholder="Nombre completo"
|
||||
oninput="actualizarAvatar(this.value)">
|
||||
<label for="pac-nombre">Nombre completo <span class="text-danger">*</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="form-floating">
|
||||
<select class="form-select" name="tipo_documento" id="pac-tipo-doc">
|
||||
<option value="CC">CC — Cédula</option>
|
||||
<option value="CE">CE — Extranjería</option>
|
||||
<option value="TI">TI — Tarjeta Identidad</option>
|
||||
<option value="PA">PA — Pasaporte</option>
|
||||
<option value="DE">DE — Doc. Extranjero</option>
|
||||
<option value="NIT">NIT</option>
|
||||
<option value="RC">RC — Reg. Civil</option>
|
||||
</select>
|
||||
<label for="pac-tipo-doc">Tipo documento</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control" name="numero_documento" id="pac-doc" placeholder="Número documento">
|
||||
<label for="pac-doc">Número documento</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="form-floating">
|
||||
<input type="date" class="form-control" name="fecha_nacimiento" id="pac-fnac" placeholder="Fecha nacimiento">
|
||||
<label for="pac-fnac">Fecha nacimiento</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contacto -->
|
||||
<div class="form-section-label mt-3"><i class="fas fa-phone"></i> Contacto</div>
|
||||
<div class="row g-2">
|
||||
<div class="col-sm-5">
|
||||
<label class="form-label small fw-semibold mb-1">Teléfono</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<select id="pac-tel-prefijo" class="form-select form-select-sm" style="max-width:76px">
|
||||
<option value="57" selected>🇨🇴 57</option>
|
||||
<option value="58">🇻🇪 58</option>
|
||||
<option value="1">🇺🇸 1</option>
|
||||
</select>
|
||||
<input type="tel" class="form-control form-control-sm" name="telefono" id="pac-tel" placeholder="3001234567">
|
||||
<div class="form-section">
|
||||
<div class="form-section-label"><i class="fas fa-phone"></i> Contacto</div>
|
||||
<div class="row g-2">
|
||||
<div class="col-sm-5">
|
||||
<label class="form-label small fw-semibold mb-1" style="color:#64748b">Teléfono</label>
|
||||
<div class="input-group">
|
||||
<select id="pac-tel-prefijo" class="form-select" style="max-width:82px;border-color:#dde3ed;border-radius:.45rem 0 0 .45rem;font-size:.875rem">
|
||||
<option value="57" selected>🇨🇴 57</option>
|
||||
<option value="58">🇻🇪 58</option>
|
||||
<option value="1">🇺🇸 1</option>
|
||||
</select>
|
||||
<input type="tel" class="form-control" name="telefono" id="pac-tel"
|
||||
placeholder="3001234567" style="border-radius:0 .45rem .45rem 0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="form-floating">
|
||||
<input type="email" class="form-control" name="email" id="pac-email" placeholder="Email">
|
||||
<label for="pac-email">Email</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="form-floating">
|
||||
<select class="form-select" name="genero" id="pac-genero">
|
||||
<option value="">—</option>
|
||||
<option value="M">Masculino</option>
|
||||
<option value="F">Femenino</option>
|
||||
<option value="O">Otro</option>
|
||||
</select>
|
||||
<label for="pac-genero">Género</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label small fw-semibold mb-1">Email</label>
|
||||
<input type="email" class="form-control form-control-sm" name="email" id="pac-email" placeholder="correo@ejemplo.com">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label small fw-semibold mb-1">Género</label>
|
||||
<select class="form-select form-select-sm" name="genero" id="pac-genero">
|
||||
<option value="">—</option>
|
||||
<option value="M">Masculino</option>
|
||||
<option value="F">Femenino</option>
|
||||
<option value="O">Otro</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ubicación -->
|
||||
<div class="form-section-label mt-3"><i class="fas fa-map-marker-alt"></i> Ubicación y EPS</div>
|
||||
<div class="row g-2">
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label small fw-semibold mb-1">EPS</label>
|
||||
<input type="text" class="form-control form-control-sm" name="eps" id="pac-eps" placeholder="EPS del paciente">
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label small fw-semibold mb-1">Ciudad</label>
|
||||
<input type="text" class="form-control form-control-sm" name="ciudad" id="pac-ciudad">
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label small fw-semibold mb-1">Barrio</label>
|
||||
<input type="text" class="form-control form-control-sm" name="barrio" id="pac-barrio">
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label small fw-semibold mb-1">Dirección</label>
|
||||
<input type="text" class="form-control form-control-sm" name="direccion" id="pac-dir">
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label small fw-semibold mb-1">Notas internas</label>
|
||||
<textarea class="form-control form-control-sm" name="notas_admin" id="pac-notas" rows="2" placeholder="Observaciones o notas adicionales…"></textarea>
|
||||
<!-- Ubicación y EPS -->
|
||||
<div class="form-section">
|
||||
<div class="form-section-label"><i class="fas fa-map-marker-alt"></i> Ubicación y EPS</div>
|
||||
<div class="row g-2">
|
||||
<div class="col-sm-4">
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control" name="eps" id="pac-eps" placeholder="EPS">
|
||||
<label for="pac-eps">EPS</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control" name="ciudad" id="pac-ciudad" placeholder="Ciudad">
|
||||
<label for="pac-ciudad">Ciudad</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control" name="barrio" id="pac-barrio" placeholder="Barrio">
|
||||
<label for="pac-barrio">Barrio</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control" name="direccion" id="pac-dir" placeholder="Dirección">
|
||||
<label for="pac-dir">Dirección</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="form-floating">
|
||||
<textarea class="form-control" name="notas_admin" id="pac-notas"
|
||||
placeholder="Notas internas" style="height:72px"></textarea>
|
||||
<label for="pac-notas">Notas internas</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer py-2 border-top">
|
||||
<button type="button" class="btn btn-sm btn-light" data-bs-dismiss="modal">Cancelar</button>
|
||||
<button type="button" class="btn btn-sm" style="background:var(--brand);color:#fff" onclick="guardarPaciente()">
|
||||
<i class="fas fa-save me-1"></i> Guardar
|
||||
|
||||
<div class="modal-footer-brand">
|
||||
<button type="button" class="btn btn-sm btn-light px-3" data-bs-dismiss="modal">
|
||||
<i class="fas fa-times me-1"></i>Cancelar
|
||||
</button>
|
||||
<button type="button" class="btn-brand-solid" onclick="guardarPaciente()">
|
||||
<i class="fas fa-save me-1"></i> Guardar paciente
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -388,13 +466,24 @@ function cerrarDetalle() {
|
||||
}
|
||||
|
||||
// ── Formulario ─────────────────────────────────────────────────────────────
|
||||
function actualizarAvatar(nombre) {
|
||||
const av = document.getElementById('modal-avatar');
|
||||
if (!av) return;
|
||||
const partes = nombre.trim().split(/\s+/).filter(Boolean);
|
||||
av.textContent = partes.length >= 2
|
||||
? (partes[0][0] + partes[1][0]).toUpperCase()
|
||||
: (partes[0]?.[0] || '?').toUpperCase();
|
||||
}
|
||||
|
||||
function abrirFormulario(p = null) {
|
||||
const form = document.getElementById('form-paciente');
|
||||
form.reset();
|
||||
document.getElementById('pac-id').value = p ? p.id : '';
|
||||
document.getElementById('modal-titulo').innerHTML = p
|
||||
? `<i class="fas fa-pen me-2"></i>Editar Paciente`
|
||||
: `<i class="fas fa-user-plus me-2"></i>Nuevo Paciente`;
|
||||
document.getElementById('modal-titulo').textContent = p ? 'Editar Paciente' : 'Nuevo Paciente';
|
||||
document.getElementById('modal-subtitulo').textContent = p
|
||||
? (p.nombre_completo || 'Actualiza los datos')
|
||||
: 'Completa los datos del paciente';
|
||||
actualizarAvatar(p?.nombre_completo || '');
|
||||
|
||||
if (p) {
|
||||
document.getElementById('pac-nombre').value = p.nombre_completo || '';
|
||||
|
||||
Reference in New Issue
Block a user