Cargando…

Esto está tardando más de lo esperado.

Volver al centro de ayuda

Marca e interfaz

El nombre, el logotipo, los colores, las fuentes y los componentes de formulario con los que se construye cada pantalla.

Cada pantalla del kit se construye con las mismas pocas cosas: un nombre, dos archivos de imagen, siete tokens de color, una pila de fuentes y un conjunto de componentes Blade. Cámbialos una vez y toda la interfaz los sigue, panel de administración y correos incluidos. Esta guía dice dónde vive cada uno, qué lo lee y qué componente usar cuando construyas un formulario propio.

Nombre, logotipo e icono

Qué Dónde se define Valor por omisión Dónde aparece
Nombre APP_NAME en .env Laravel Título del navegador, textos alt de imágenes, el menú y el pie públicos, el nombre de la PWA, los correos
Logotipo logo en config/app.php images/logo.svg El encabezado de cada correo, el panel lateral móvil del área con sesión
Icono icon en config/app.php images/icon.svg El favicon, el menú lateral de escritorio y la barra superior del área con sesión, cada pantalla de inicio de sesión, la imagen por omisión de una notificación, la base de los iconos de la PWA

Ambas rutas son relativas a public/, así que el cambio más rápido es reemplazar los dos archivos y conservar las claves. SVG es lo que viene; cualquier formato que un navegador renderice funciona. El logotipo se dibuja a unos 36 píxeles de alto y el icono entre 36 y 96, así que dales a ambos fondo transparente y suficiente contraste sobre blanco.

La landing pública muestra el nombre como texto, no el logotipo. Su pie imprime un bloque "Desarrollado por Weblabor" desde resources/views/layouts/web.blade.php, que es un archivo compartido: editarlo funciona, y vas a resolver esa edición otra vez en cada merge de la base.

Los iconos de la PWA

Cuando APP_PWA=true el navegador pide además un juego de iconos PNG y pantallas de inicio. config/laravelpwa.php los lista bajo public/images/icons/, junto con el theme_color y el background_color que usa la app instalada. Un comando genera todos los archivos a partir de una sola imagen:

php artisan pwa:generate-assets

Pregunta por la imagen de origen, con la ruta de config/app.php como valor por omisión, y por dos colores hexadecimales para el degradado de las pantallas de inicio. El origen debe ser cuadrado y de al menos 512 por 512 píxeles, en un formato que la biblioteca GD lea, así que dale un PNG y no el icono SVG. El resto del manifiesto está en Web push y la PWA.

Colores

Las vistas nunca nombran una paleta de Tailwind. Usan tokens semánticos, y cada token se asigna a una paleta una sola vez, en resources/css/app.css, dentro del bloque @theme inline. El proyecto corre Tailwind 4, así que no hay tailwind.config.js: el archivo CSS es la configuración.

Token Paleta por omisión Papel
primary teal Tu marca: botones, enlaces, estados activos, la barra de progreso
secondary gray Controles apagados y botones secundarios
default slate Texto, bordes y superficies de las páginas públicas
positive emerald Éxito: insignias de verificado, confirmaciones
negative red Errores, acciones destructivas, mensajes de validación
warning amber Advertencias: el banner de recordatorio del PIN, una guía sin traducir
info blue Información neutral

Cada token tiene los once tonos de 50 a 950, así que bg-primary-600, text-negative-600 o border-warning-400 existen todos. primary tiene además un valor sin tono, --color-primary, que usan clases como bg-primary y text-primary y la barra de progreso de carga de página.

Para cambiar la marca, edita la asignación y vuelve a compilar:

--color-primary: var(--color-indigo-700);
--color-primary-50:  var(--color-indigo-50);
--color-primary-100: var(--color-indigo-100);
/* ... hasta 950 */
npm run build

Cualquier paleta de Tailwind funciona del lado derecho, y también un color literal como #0f766e cuando la marca no tiene paleta. Mantén el --color-primary sin tono alineado con el tono que quieres que usen los botones.

Cambiar la asignación cambia toda la interfaz porque nada más conoce la paleta. Los componentes de WireUI comparten los mismos nombres, primary, secondary, positive, negative, warning e info, y config/wireui.php fija primary como su color por omisión, así que <x-button positive> y una insignia bg-positive-600 toman los mismos tonos. El panel de administración, los correos y tus propias vistas heredan el cambio sin edición propia.

La interfaz tiene un solo tema claro. Hay una variante dark declarada en el CSS, pero ningún interruptor agrega la clase dark a la página, así que las clases dark: no se usan en ningún lado y no necesitas escribirlas. El área con sesión descansa sobre #fafafe; las páginas públicas sobre blanco.

Fuentes e iconos

--font-sans en resources/css/app.css nombra Inter primero y luego las fuentes del sistema. Ninguna hoja de estilos carga Inter, así que el navegador usa la fuente del sistema hasta que agregues la fuente tú, ya sea con un <link> en el <head> de resources/views/layouts/base.blade.php o con un @font-face alojado por ti en app.css.

Los iconos vienen de dos fuentes. En todo el área con sesión y el panel de administración, <x-icon name="user" /> dibuja un Heroicon a través de WireUI, con variant="solid", mini y class como atributos habituales. La landing pública carga además Material Symbols Outlined y los dibuja como <span class="material-symbols-outlined">bolt</span>.

Componentes de formulario

Los formularios se escriben con componentes, nunca con elementos <input> crudos, para que cada campo tenga la misma etiqueta, mensaje de error, anillo de foco y enlace con Livewire. Existen dos familias: los componentes de WireUI sobre los que está construido el kit, y los componentes que el kit agrega donde WireUI no tiene respuesta.

De WireUI

wireui/wireui está instalado sin prefijo, así que sus componentes se llaman como <x-input>. config/wireui.php guarda sus valores por omisión: una sombra base, esquinas redondeadas medianas y primary como color. Los que más vas a usar:

Componente Propósito Atributos principales Ejemplo
<x-input> Campos de texto y número label, placeholder, type, hint, icon, prefix, suffix <x-input :label="__('Name')" wire:model="name" />
<x-password> Contraseña con botón de mostrar u ocultar label, autocomplete <x-password :label="__('Password')" wire:model="password" />
<x-select> Lista desplegable con búsqueda label, options, option-key-value, option-label, option-value, multiselect, clearable <x-select :label="__('Plan')" wire:model="plan" :options="$plans" option-key-value />
<x-native-select> <select> simple label, options <x-native-select :label="__('Size')" :options="['S', 'M']" wire:model="size" />
<x-textarea> Texto de varias líneas label, rows <x-textarea :label="__('Notes')" wire:model="notes" />
<x-checkbox>, <x-toggle>, <x-radio> Booleanos y opciones label, value, left-label <x-toggle :label="__('Send me email')" wire:model="send_mail" />
<x-datetime-picker> Calendario con hora ver <x-date-input> abajo prefiere <x-date-input>
<x-phone> Número telefónico con máscara por país label, placeholder prefiere <x-phone-input>
<x-button> Botones y enlaces label, primary, positive, negative, flat, outline, icon, href, spinner, full, lg <x-button type="submit" primary :label="__('Save')" />
<x-card> Sección en caja con título y slot de pie title <x-card :title="__('Deployment')">...</x-card>
<x-alert>, <x-badge> Mensajes y etiquetas title, info, positive, negative, warning <x-alert :title="__('Saved')" positive />
<x-icon> Heroicon name, variant, mini <x-icon name="check-circle" class="h-4 w-4" />

<x-notifications /> y <x-dialog /> se colocan una sola vez, en el layout base, y reciben lo que un componente manda con $this->notification()->success(...) o $this->dialog()->confirm([...]) después de use WireUi\Traits\WireUiActions;. Los modales se abren a través del paquete wire-elements/modal con $this->dispatch('openModal', 'component.name', [...]).

Del kit

Éstos viven en resources/views/components/, con su clase PHP en app/View/Components/ y, donde necesitan estado, un subcomponente Livewire en app/Livewire/Shared/Inputs/. Cada uno funciona sólo con wire:model; todos los demás atributos son opcionales.

Componente Propósito Atributos principales Ejemplo
<x-date-input> Fecha, hora o ambas, guardadas en UTC y mostradas en la zona horaria del usuario label; type (date, time, datetime-local para un campo nativo, omitido para el calendario de WireUI); min, max, step; para el calendario también without-time, interval, time-format, clearable, disable-past-dates, parse-format, display-format <x-date-input :label="__('Birth date')" wire:model="user.birth_date" type="date" />
<x-email-input> Correo con insignia de Verificado / No verificado y un enlace Verificar ahora que abre el modal de OTP label, placeholder <x-email-input :label="__('Email')" wire:model.live="email" />
<x-phone-input> Teléfono con máscara por país, la misma insignia y el enlace de verificar cuando se exige label, placeholder, validation-required, verified-at, dispatch-context <x-phone-input :label="__('Phone')" wire:model.live="phone" :validation-required="true" :verified-at="$user->phone_verified_at" />
<x-domain-input> Un nombre de host y su TLD en dos campos, armados en un solo valor label, name, placeholder; wire:model o value <x-domain-input :label="__('Website')" wire:model="website" name="website" />
<x-categories> Una o varias categorías de la tabla de categorías type (limita las opciones a un tipo de categoría), is-multiple, show-label, initial-value <x-categories wire:model="category_ids" type="posts" :is-multiple="true" />
<x-country-select>, <x-division-select> País, luego estado, luego ciudad, del paquete weblabormx/world-ui label, placeholder; id de la división padre en <x-division-select> <x-division-select wire:model.live="state" :id="$country" />
<x-audio-player> Reproductor con forma de onda, barra de avance, velocidad y volumen audio (URL; no renderiza nada cuando está vacío), label, compact (sólo botón de reproducir, tiempos en un tooltip) <x-audio-player audio="https://your-project.test/voice.mp3" :label="__('Voice message')" />

Los campos verificados disparan un evento Livewire identity-verified cuando el OTP tiene éxito; el de correo lo hace con su columna de wire:model como contexto, el de teléfono con dispatch-context cuando se le da. El flujo, los proveedores de SMS y correo y la carga del evento están en Verifica correo y teléfono.

<x-date-input> usa <x-datetime-picker> cuando se omite type y un <x-input type="date"> nativo en cualquier otro caso. Ambos leen y escriben el valor por el mismo enlace, así que la propiedad Livewire recibe una cadena que el cast datetime del modelo convierte a UTC. No mezcles un <input type="date"> crudo: es lo que el componente existe para reemplazar.

<x-audio-player.play-button size="md" /> y <x-audio-player.volume-icon /> pueden usarse por su cuenta dentro de un elemento que tenga x-data="audioPlayer(url)".

Componentes de layout

Componente Qué hace
<x-language-switcher /> Los enlaces EN / ES de los idiomas de config/app.php. Se renderiza sólo para visitantes: una cuenta con sesión lee su idioma de su perfil
<x-loading-overlay /> El spinner de pantalla completa, colocado una vez en el layout base; ver la siguiente sección
<x-system-warnings /> El banner de advertencia del área con sesión: hoy le recuerda a un usuario sin PIN que configure uno cuando el PIN está activo
<x-sidebar-menu :items :groups /> El menú lateral de las áreas de administración y cuenta: items son enlaces de primer nivel (name, url, icon, exact, show, order) y groups secciones plegables que llenan los recursos de administración
<x-landing.hero>, <x-landing.block>, <x-landing.cta> Los bloques de una página de característica: un título con una promesa, una imagen con un párrafo y un enlace opcional a una guía, y la llamada a la acción de cierre

Estados de carga

Una capa de pantalla completa en <x-loading-overlay /> cubre la página mientras algo está en curso, controlada por resources/js/app.js. Aparece por sí sola durante la navegación entre páginas y durante cualquier formulario enviado con wire:submit. Para una acción fuera de un formulario, agrega el atributo spinner al elemento que dispara la petición:

<x-button wire:click="confirmMigration" spinner :label="__('Confirm')" />

Para una subida de archivo el atributo va en el propio <input type="file">, no en el botón que abre el selector, porque la petición empieza cuando el campo cambia.

No agregues spinner a campos wire:model.live, filtros, cajas de búsqueda ni cambios de pestaña: eso debe sentirse instantáneo y nunca bloquear la pantalla. Si la capa se queda más de tres segundos muestra un botón Recargar, para que una pantalla nunca se quede atorada sin salida.

Escribe tu propio campo

Antes de escribir uno, revisa la tabla de arriba. Cuando ninguno encaje, conserva el mismo contrato: wire:model es el único atributo obligatorio y todo lo demás tiene un valor por omisión, para que quien lo use nunca arme formatos, zonas horarias u opciones a mano. Un componente sin estado en el servidor es un solo archivo Blade que envuelve <x-input {{ $attributes }} />. Un componente que consulta cosas o guarda estado sigue a <x-date-input>: un archivo Blade en resources/views/components/, una clase en app/View/Components/ que resuelve el valor actual desde la ruta de wire:model, y un subcomponente Livewire en app/Livewire/Shared/Inputs/ que renderiza el campo y escribe de regreso por el enlace. Usa dentro los tokens semánticos de color y seguirá cada cambio de marca junto con el resto.