Search by

luinuxscl / lnx-ui

luinuxscl

Componentes UI compartidos para aplicaciones derivadas del kit lnx (Blade anónimos, override-friendly).

Package info

github.com/luinuxscl/lnx-ui

Language:Blade

pkg:composer/luinuxscl/lnx-ui

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.17.0 2026-10-25 13:12 UTC

README

Licencia: MIT

Componentes UI compartidos para las aplicaciones derivadas del kit lnx. Es un paquete Composer de Blade anónimos, pensado para tener una sola fuente de componentes entre proyectos y permitir que cada app los sobrescriba sin tocar el paquete.

Licencia MIT: parte del kit. Úsalo y modifícalo libremente.

Instalación

En una app lnx, añade el repositorio VCS público y requiere el paquete:

composer config repositories.lnx-ui vcs https://github.com/luinuxscl/lnx-ui.git
composer require luinuxscl/lnx-ui

En desarrollo local del propio paquete puedes usar un repositorio path en lugar del VCS.

El LnxUiServiceProvider se autodescubre gracias a extra.laravel.providers: no hay que registrarlo a mano.

Tailwind 4

Las clases dentro de vendor/ no se detectan solas. Añade una línea a resources/css/app.css:

@source '../../vendor/luinuxscl/lnx-ui/resources/views';

Uso

Los componentes viven bajo el namespace lnx-ui:

<x-lnx-ui::trend-card label="Sales" value="2.968" change="+3.2%" :series="[10, 20, 30]" color="emerald" />

Sobrescribir un componente

loadViewsFrom registra primero resources/views/vendor/lnx-ui, así que una app puede reemplazar cualquier componente creando el mismo archivo dentro de resources/views/vendor/lnx-ui/components/:

resources/views/vendor/lnx-ui/components/trend-card.blade.php

Para publicar todas las vistas del paquete y editarlas:

php artisan vendor:publish --tag=lnx-ui-views

Galería de diseño

El paquete incluye la vista lnx-ui::design-gallery: el catálogo de componentes agrupados por tipo, cada uno con un nombre y un ancla estable (#<nombre>) para referenciarlo con la IA. Es contenido sin layout; la app lo envuelve en su propio layout y decide la ruta y el gating:

{{-- resources/views/design-gallery.blade.php --}}
<x-layouts::app :title="__('Design gallery')" :breadcrumbs="[['label' => __('Design gallery')]]">
    @include('lnx-ui::design-gallery')
</x-layouts::app>

Las cadenas de la galería viven en el namespace lnx-ui::design-gallery (lang/{en,es}/design-gallery.php) y se pueden sobrescribir en lang/vendor/lnx-ui/{locale}/design-gallery.php.

Componentes disponibles

Componente Props
x-lnx-ui::stat label, value, icon, color
x-lnx-ui::stat-card label, value, icon, color (envuelve stat en flux:card)
x-lnx-ui::statistics-panel title, updated-label y updated-icon (opcionales); slots de métricas, actions, description y empty
x-lnx-ui::trend-card label, value, change, series (array), color
x-lnx-ui::chart-card label, value; description, help, change, trend, change-style (text por defecto), series (array), chart (line/bar), labels (array), color
x-lnx-ui::metric-card label, value, icon; description, help, change, trend, change-style (badge por defecto), color
x-lnx-ui::tool-card title, description, icon, href, color, external
x-lnx-ui::resource-card title, description, icon, eyebrow, href, external, color; slots badges, tags, meta, actions
x-lnx-ui::properties-card title, description, items (array de label, value, href, icon), columns (1 o 2), empty; slots actions y contenido libre
x-lnx-ui::timeline title, description, items (array de title, description, meta, time, datetime, icon, color), empty; slots actions, empty y contenido libre
x-lnx-ui::placeholder-pattern id (opcional)
x-lnx-ui::auth-header title, description
x-lnx-ui::auth-session-status status
x-lnx-ui::chip label, icon, color; el slot es el fallback
x-lnx-ui::media-cell title, description, icon, image, href, color
x-lnx-ui::summary-card label, value, caption, change, icon, color
x-lnx-ui::page-header title, subtitle, icon, color; slot actions
x-lnx-ui::data-table title (opcional), description, filters-label, paginate, table-class, container-class; slots filters, toolbar, actions y el contenido de la tabla
x-lnx-ui::data-table-inline title (opcional), description, paginate, table-class, container-class; slots filters, filtersActions, toolbar, actions y el contenido de la tabla
x-lnx-ui::mail-list-item sender, email, avatar, subject, preview, time, unread, starred, selected, badge (['label' => …, 'color' => …]), href, select-label, star-label; slots select, star
x-lnx-ui::attachment-card name, size, icon, color, href; slot action
x-lnx-ui::presence-list title (opcional), users (array de name, avatar, line, online)
x-lnx-ui::mail-viewer sender, email, avatar, subject, date; slots actions, attachments, reply, footer y el cuerpo por defecto
x-lnx-ui::rich-text-editor value, label, placeholder, disabled; slot actions; usa wire:model/x-model

color acepta accent (predeterminado), violet, cyan, rose, emerald, blue y amber.

Los componentes de correo (mail-list-item, attachment-card, presence-list, mail-viewer) son presentacionales: el consumidor aporta los textos ya traducidos y los datos ya formateados. Sus etiquetas accesibles viven en el namespace lnx-ui::components (lang/{en,es}/components.php) y se pueden sobrescribir con select-label/star-label.

page-header es el encabezado estándar de una página: un solo <h1> con el título, un subtítulo opcional y un badge de icono opcional. Las acciones de la página van en el slot actions, alineadas a la derecha:

<x-lnx-ui::page-header
    :title="__('Users')"
    :subtitle="__('Manage accounts, roles and invitations.')"
    icon="users"
    color="blue"
>
    <x-slot:actions>
        <flux:button variant="primary" icon="plus">{{ __('Invite user') }}</flux:button>
    </x-slot:actions>
</x-lnx-ui::page-header>

data-table-inline es la variante compacta de data-table para barras de filtros: no muestra el rótulo de filtros y coloca el slot filtersActions (exportar, limpiar, etc.) alineado a la derecha dentro de la misma fila que filters, ajustándose a ancho completo en pantallas estrechas.

data-table renderiza el title solo si se entrega: sin título ni slot filters, desaparece la fila superior. container-class se reenvía al contenedor de flux:table (el que envuelve la tabla, el pie y la paginación), útil para acotar la altura y fijar el encabezado (por ejemplo container-class="max-h-[70vh] overflow-auto" junto con sticky en flux:table.columns). No lo uses para el ancho.

En pantallas estrechas no fuerces un ancho mínimo con table-class="min-w-[…]": crea un scroll horizontal sin barra visible que la tarjeta recorta y deja columnas inalcanzables. En su lugar, oculta columnas por breakpoint (max-sm:hidden, max-md:hidden, max-lg:hidden, max-xl:hidden) en la columna de flux:table.columns y en su celda, de modo que la tabla siempre quepa sin scroll horizontal. La galería (#data-table) es el ejemplo de referencia. Si de verdad necesitas un suelo de ancho, que sea responsivo y coherente con las columnas que ocultas.

En chart-card y metric-card, la variación (change) se colorea en verde o rojo según su signo; trend (up/down) lo sobrescribe. El contenedor asigna el ancho, normalmente col-span-12 md:col-span-6 xl:col-span-3.

En chart-card y metric-card, help añade un texto de ayuda inline bajo la descripción para explicar conceptos poco obvios. Cuando se entrega, la tarjeta se expone como grupo accesible (role="group") asociado a la etiqueta y a la ayuda con aria-labelledby/aria-describedby; sin help, el render es idéntico al anterior:

<x-lnx-ui::metric-card :label="__('Total sales')" value="24.67k" icon="shopping-bag" :help="__('Includes confirmed and pending records.')" />

Editor de texto enriquecido

x-lnx-ui::rich-text-editor es un editor TipTap (ProseMirror) con toolbar accesible para negrita, cursiva, h2/h3, listas, cita, enlaces y deshacer/rehacer. El HTML resultante es responsabilidad de la app: siempre debe sanearse en el servidor antes de guardarlo.

<x-lnx-ui::rich-text-editor
    wire:model="bodyHtml"
    :value="$bodyHtml"
    :label="__('Body')"
    :placeholder="__('Start writing…')"
>
    <x-slot:actions>
        <button type="button" x-on:click="assist('improve')">{{ __('Improve') }}</button>
    </x-slot:actions>
</x-lnx-ui::rich-text-editor>

El componente usa x-modelable="html", así que funciona con wire:model en Livewire y con x-model en Alpine. Para uso standalone, pasa el contenido inicial en value.

Dependencias JavaScript

El paquete solo distribuye el módulo ESM; las dependencias npm las instala la app consumidora:

npm install @tiptap/core @tiptap/starter-kit @tiptap/pm

Importa el módulo una sola vez en el bundle de la app:

// resources/js/app.js
import '../../vendor/luinuxscl/lnx-ui/resources/js/rich-text-editor.js';

El módulo registra el componente Alpine lnxRichText en alpine:init. Las clases Tailwind de la vista ya se detectan con el @source del paquete.

Acciones de IA y eventos

El editor no implementa IA. La app dibuja sus acciones en el slot actions y llama a assist(action), que captura la selección y emite un evento Livewire:

  • lnx-rich-text:assist ({ action, html }) — la app recibe la selección.
  • lnx-rich-text:assist-complete ({ html }) — la app devuelve el HTML saneado; el editor reemplaza la selección. Con html: null solo se reactiva el editor.
  • lnx-rich-text:set-content ({ html }) — reemplaza el contenido completo (por ejemplo, tras una acción de IA o al normalizar tras guardar).

Mientras espera la respuesta, el editor se bloquea para conservar el rango de selección. La sustitución es una sola transacción, así que se puede deshacer.

Versionado

El paquete sigue SemVer. Las apps consumidoras requieren ^1.0, de modo que las adiciones de componentes (minor) se reciben con composer update luinuxscl/lnx-ui sin tocar composer.json.

Desarrollo

composer install
vendor/bin/pest
vendor/bin/pint

Convención de extracción

Un componente se mueve a este paquete cuando es presentacional puro: no consulta la base de datos, no lee modelos del host (App\Models\*) y no depende de rutas ni servicios de la app. Los componentes acoplados al host (app-logo, user-avatar, desktop-user-menu, etc.) se quedan en la aplicación.