Átomos
Las piezas indivisibles: botones, campos, etiquetas, avatares y estados de carga. Cada ejemplo se renderiza con el CSS real del producto, así que lo que ves acá es literalmente lo que vas a ver en la app o en el sitio.
Botones
Acción principal, secundaria y destructiva. Un botón primario por pantalla.
styles/app-shell.css
<div class="d-flex flex-wrap gap-2 align-items-center">
<button class="btn btn-gm-primary">Guardar</button>
<button class="btn btn-gm-secondary">Cancelar</button>
<button class="btn btn-gm-success">Aprobar</button>
<button class="btn btn-gm-danger">Eliminar</button>
<button class="btn btn-gm-primary btn-sm"><i class="fas fa-plus me-1"></i> Nuevo</button>
<button class="btn btn-outline-primary">Alternativa</button>
<button class="btn btn-gm-primary" disabled>Deshabilitado</button>
</div>
.gm-ripple automático desde js/animations.js. No pongas dos primarios compitiendo en la misma vista.Etiquetas de estado
El estado de un registro en una tabla o tarjeta. Los fondos suaves ya traen su color de texto.
styles/app-shell.css
<div class="d-flex flex-wrap gap-2 align-items-center">
<span class="status-pill bg-success-soft">Completado</span>
<span class="status-pill bg-warning-soft">En proceso</span>
<span class="status-pill bg-primary-soft">Programado</span>
<span class="status-pill bg-info-soft">En revisión</span>
<span class="badge bg-light text-secondary border">#1042</span>
</div>
.badge-gm (está afinado para .table-gm-container); suelto, .status-pill.Chips
Atributos de un registro en su ficha: estado, tipo, avisos.
GrupoMecsaProyectos/pages/proyecto.php
<div class="pd-chips">
<span class="pd-chip pd-chip-state">En ejecución</span>
<span class="pd-chip">Mantenimiento industrial</span>
<span class="pd-chip pd-chip-ok"><i class="fas fa-check"></i> Facturado</span>
<span class="pd-chip pd-chip-warn"><i class="fas fa-triangle-exclamation"></i> Vencido</span>
</div>
Campos de formulario
Entradas, selects y áreas de texto. Bootstrap tal cual, ya tematizado por los tokens.
styles/app-shell.css
<div class="row g-3">
<div class="col-md-4">
<label class="form-label">Cliente</label>
<input type="text" class="form-control" placeholder="Nombre o cédula jurídica">
</div>
<div class="col-md-4">
<label class="form-label">Tipo de trabajo</label>
<select class="form-select">
<option>Mantenimiento</option>
<option>Instalación</option>
</select>
</div>
<div class="col-md-4">
<div class="form-floating">
<input type="email" class="form-control" id="correo" placeholder="correo">
<label for="correo">Correo</label>
</div>
</div>
<div class="col-12">
<label class="form-label">Observaciones</label>
<textarea class="form-control" rows="2" placeholder="Opcional"></textarea>
</div>
</div>
bg-white en un campo: el fondo sale de --input-bg y en oscuro quedaría blanco.Casillas, radios e interruptores
Interruptor para algo que se aplica al instante; casilla para algo que se guarda con el formulario.
styles/app-shell.css
<div class="d-flex flex-wrap gap-4 align-items-center">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="chk1" checked>
<label class="form-check-label" for="chk1">Cliente activo</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="moneda" id="rad1" checked>
<label class="form-check-label" for="rad1">Colones</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="moneda" id="rad2">
<label class="form-check-label" for="rad2">Dólares</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="sw1" checked>
<label class="form-check-label" for="sw1">Notificar por correo</label>
</div>
</div>
Avatares e iconos
Inicial sobre navy cuando no hay foto. El icono en pastilla acompaña a los indicadores.
styles/app-shell.css
<div class="d-flex align-items-center gap-3 flex-wrap">
<div class="topbar-avatar">E</div>
<div class="gm-avatar-table">MJ</div>
<div class="icon-circle bg-primary bg-opacity-10 text-primary"><i class="fas fa-users"></i></div>
<div class="icon-circle bg-success bg-opacity-10 text-success"><i class="fas fa-user-check"></i></div>
<div class="icon-circle bg-danger bg-opacity-10 text-danger"><i class="fas fa-user-slash"></i></div>
<div class="icon-circle bg-warning bg-opacity-10 text-warning"><i class="fas fa-clock"></i></div>
</div>
Estados de carga
Spinner para una acción puntual; esqueleto cuando se está cargando contenido con forma conocida.
styles/app-shell.css
<div class="d-flex align-items-center gap-3 mb-4">
<span class="gm-spinner"></span>
<button class="btn btn-gm-primary" disabled>
<span class="spinner-border spinner-border-sm me-1"></span> Guardando…
</button>
</div>
<div style="max-width:420px">
<div class="skeleton skeleton-line skeleton-title"></div>
<div class="skeleton skeleton-line"></div>
<div class="skeleton skeleton-line skeleton-line-short"></div>
</div>
Contador animado
Cifra que sube al entrar en pantalla. Lo maneja js/animations.js con el atributo data-counter.
starter/js/animations.js
<div class="d-flex gap-5">
<div>
<div class="kpi-label">Proyectos activos</div>
<div class="kpi-value" data-counter="248">0</div>
</div>
<div>
<div class="kpi-label">Facturado del mes</div>
<div class="kpi-value text-success" data-counter="8400000">0</div>
</div>
</div>
Tipografía
Inter en 5 pesos. Las clases gm existen igual en la web y en las apps.
styles/tokens.css
<p class="h1-gm">Encabezado H1</p>
<p class="h2-gm">Encabezado H2</p>
<p class="h3-gm">Encabezado H3</p>
<p class="h4-gm">Encabezado H4</p>
<p class="p-gm">Texto de párrafo (Inter Regular).</p>
<p class="p-gm text-muted mb-0">Texto secundario, metadatos y ayudas.</p>
Botones del sitio
Los del sitio público: más grandes y con más aire que los de las apps.
GrupoMecsa/styles/components/_buttons_forms.scss
<div class="d-flex flex-wrap gap-2 align-items-center">
<button class="btn btn-gm-primary">Solicitar cotización</button>
<button class="btn btn-gm-secondary">Ver servicios</button>
<button class="btn btn-gm-outline-secondary">Más información</button>
<a href="#" class="btn-gm-link-primary">Seguir leyendo</a>
</div>
Etiquetas del sitio
Categorías de blog, estados de pedido y distintivos de producto.
GrupoMecsa/styles/components/_buttons_forms.scss
<div class="d-flex flex-wrap gap-2 align-items-center">
<span class="badge text-bg-mg-primary">Protección contra rayos</span>
<span class="badge text-bg-mg-secondary">Asfalto</span>
<span class="badge text-bg-mg-success">Entregado</span>
<span class="badge text-bg-mg-warning">Pendiente de pago</span>
<span class="badge text-bg-mg-danger">Cancelado</span>
</div>
Buscador del sitio
El buscador del encabezado: alimenta el autocompletado de productos y servicios.
GrupoMecsa/components/header.php
<form class="d-flex form-search-gm w-100" role="search">
<div class="gm-search-autocomplete flex-grow-1 position-relative">
<input class="form-control form-control-gm-search w-100" type="search" name="q"
placeholder="Buscar..." aria-label="Buscar" autocomplete="off">
</div>
<button class="btn btn-outline-secondary btn-gm-secondary btn-gm-search" type="submit" aria-label="Buscar en el sitio">
<i class="fa-solid fa-magnifying-glass" aria-hidden="true"></i>
</button>
</form>
Estrellas de valoración
La calificación de un producto: promedio, estrellas y cantidad de reseñas.
GrupoMecsa/scripts/product.js
<!-- En la tarjeta del catálogo (dentro de .product-card, texto chico) -->
<div class="product-card">
<div class="product-rating text-warning">
<i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i><i class="fa-regular fa-star"></i>
<span class="rating-number">4,2</span>
<span class="review-count">(38 reseñas)</span>
</div>
</div>
<!-- Sueltas, para la ficha del producto -->
<div class="rating-stars">
<i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i>
<i class="fa-regular fa-star"></i><i class="fa-regular fa-star"></i>
</div>
fa-solid las llenas y fa-regular las vacías, redondeando el promedio. El tamaño depende del contexto: .rating-number dentro de .product-card es chico, y suelto (ficha de producto) mide 3,5 rem.Esqueleto de carga
Lo que se ve mientras carga el catálogo. Tiene la forma de la tarjeta que va a llegar.
GrupoMecsa/scripts/maintienda.js
<div class="row" style="max-width:560px">
<div class="col-6 mb-4">
<div class="skeleton-card">
<div class="skeleton skeleton-img"></div>
<div class="skeleton-body">
<div class="skeleton skeleton-text skeleton-title"></div>
<div class="skeleton skeleton-text"></div>
<div class="skeleton skeleton-text skeleton-price"></div>
</div>
</div>
</div>
<div class="col-6 mb-4">
<div class="skeleton-card">
<div class="skeleton skeleton-img"></div>
<div class="skeleton-body">
<div class="skeleton skeleton-text skeleton-title"></div>
<div class="skeleton skeleton-text"></div>
<div class="skeleton skeleton-text skeleton-price"></div>
</div>
</div>
</div>
</div>