diff --git a/apps/web/components.json b/apps/web/components.json
index 8b761f3..be3bbc5 100644
--- a/apps/web/components.json
+++ b/apps/web/components.json
@@ -10,7 +10,7 @@
"cssVariables": true,
"prefix": ""
},
- "iconLibrary": "lucide",
+ "iconLibrary": "tabler",
"aliases": {
"components": "#components",
"ui": "@repo/shadcn-ui/components",
diff --git a/docs/campos-y-plantillas-de-activos.md b/docs/campos-y-plantillas-de-activos.md
index e52d286..c4267dd 100644
--- a/docs/campos-y-plantillas-de-activos.md
+++ b/docs/campos-y-plantillas-de-activos.md
@@ -56,7 +56,7 @@ contrato actual de instantáneas.
## Iconos de plantilla
-Cada plantilla global o propia de compañía admite un icono opcional de la biblioteca Lucide existente. El formulario incluye un selector visual con nombres traducidos, selección marcada y opción «Sin icono». Las copias conservan el icono; las plantillas personalizadas permiten cambiarlo y retirarlo.
+Cada plantilla global o propia de compañía admite un icono opcional de la biblioteca Tabler Icons compartida. El formulario incluye un selector visual con nombres traducidos, selección marcada y opción «Sin icono». Las copias conservan el icono; las plantillas personalizadas permiten cambiarlo y retirarlo.
Las doce plantillas de serie incluyen iconos adecuados a cada equipo. Editar o retirar un icono conserva identidades, campos y disponibilidad; el arranque no repone los iconos retirados por el usuario.
diff --git a/docs/componentes-de-interfaz.md b/docs/componentes-de-interfaz.md
index 48c08cb..3d121c2 100644
--- a/docs/componentes-de-interfaz.md
+++ b/docs/componentes-de-interfaz.md
@@ -13,6 +13,31 @@ El [patrón de diseño de cuadros de diálogo](patron-de-dialogos.md) es la fuen
para componer grupos, columnas responsive, filas compactas y selectores. Esta guía describe
los componentes que lo implementan y sus contratos.
+## Iconografía de la aplicación
+
+El código propio utiliza `@tabler/icons-react`, con versión exacta en `@repo/rdx-ui` y
+licencia MIT. La dependencia sustituye a Lucide en la biblioteca propia y amplía el
+catálogo disponible sin cargar iconos desde servicios externos. Las importaciones de
+la aplicación y de sus componentes compartidos pasan por `@repo/rdx-ui/lib/icons`
+(o `../lib/icons` dentro del paquete). No importar las bibliotecas de iconos directamente
+en módulos ni duplicar catálogos locales para acciones comunes.
+
+`lib/icons.ts` exporta nombres semánticos estables, asociados a los componentes de
+contorno de Tabler. El tamaño se controla con las clases existentes y el color con
+`currentColor`; el trazo predeterminado de Tabler es 2. Para ajustar su grosor se utiliza
+la prop `stroke`. Los iconos decorativos mantienen `aria-hidden`; las acciones de icono
+conservan su nombre accesible traducido. Importar únicamente los iconos necesarios.
+
+Las claves persistidas de las plantillas de activos y recursos conservan su contrato:
+`laptop`, `desktop`, `mail`, `file-key`, etc. La correspondencia visual cambia a Tabler,
+sin migraciones de datos ni cambios en DTO, historial o preferencias del usuario.
+Los selectores de plantillas usan la misma correspondencia que las fichas y listados.
+
+`apps/web/components.json` declara Tabler para la generación desde la aplicación.
+`packages/shadcn-ui` conserva su implementación vendor, configuración y dependencia de
+Lucide para sus iconos internos; no modificar el código de terceros para migrar los
+iconos propios. Consultar la [API oficial de Tabler para React](https://docs.tabler.io/icons/libraries/react).
+
## Componentes actuales
- Button: volver a comprobar la conexión.
@@ -116,7 +141,8 @@ No añadir todo el catálogo ni crear envoltorios sin una necesidad concreta.
Base UI proporciona interacción accesible y gestión del foco.
class-variance-authority define variantes del botón; cn combina clases de Tailwind.
-lucide-react aporta los iconos del selector y tw-animate-css sus transiciones.
+`@tabler/icons-react` aporta los iconos del código propio y tw-animate-css sus transiciones.
+El código vendor de shadcn/ui conserva sus dependencias e iconos internos del registro.
shadcn es una herramienta de desarrollo; su hoja de estilos común se incorpora al compilar.
Guías oficiales: [monorepos](https://ui.shadcn.com/docs/monorepo) e [instalación manual](https://ui.shadcn.com/docs/installation/manual).
@@ -382,7 +408,7 @@ Los módulos conectan este componente mediante `DeleteRecordDialog`, separado de
## IconPicker
-`@repo/rdx-ui/components/icon-picker` presenta un desplegable compacto mediante `Select`, `SelectTrigger`, `SelectValue` y `SelectItem` de shadcn/ui (Base UI). Muestra el icono seleccionado y su etiqueta traducida; cada opción combina icono y texto, incluida «Sin icono». Recibe opciones (valor, etiqueta e icono), valor actual, callback, estado deshabilitado y descripción opcional enlazada mediante `aria-describedby`. Su anchura máxima en escritorio es 16 rem y se adapta al espacio disponible en móvil. La etiqueta se asocia al control y los iconos se ocultan del nombre accesible. Mantiene teclado, foco y desplazamiento del desplegable mediante la primitiva existente. No conoce entidades ni endpoints. Las plantillas de activos y recursos reutilizan el mismo componente y aportan sus iconos Lucide, traducciones y validación de claves.
+`@repo/rdx-ui/components/icon-picker` presenta un desplegable compacto mediante `Select`, `SelectTrigger`, `SelectValue` y `SelectItem` de shadcn/ui (Base UI). Muestra el icono seleccionado y su etiqueta traducida; cada opción combina icono y texto, incluida «Sin icono». Recibe opciones (valor, etiqueta e icono), valor actual, callback, estado deshabilitado y descripción opcional enlazada mediante `aria-describedby`. Su anchura máxima en escritorio es 16 rem y se adapta al espacio disponible en móvil. La etiqueta se asocia al control y los iconos se ocultan del nombre accesible. Mantiene teclado, foco y desplazamiento del desplegable mediante la primitiva existente. No conoce entidades ni endpoints. Las plantillas de activos y recursos reutilizan el mismo componente y aportan sus iconos Tabler, traducciones y validación de claves.
## Consulta compacta de plantillas
diff --git a/docs/recursos-campos-y-plantillas.md b/docs/recursos-campos-y-plantillas.md
index ab2c882..2052f30 100644
--- a/docs/recursos-campos-y-plantillas.md
+++ b/docs/recursos-campos-y-plantillas.md
@@ -122,7 +122,7 @@ presentación completa. No cambia el contrato HTTP, la persistencia ni la valida
## Iconos de plantillas
-Las ocho plantillas de serie incluyen un icono Lucide: correo para buzones, llave para
+Las ocho plantillas de serie incluyen un icono Tabler: correo para buzones, llave para
accesos, carpeta para carpetas compartidas, auriculares para asistencia, monitor para
sistemas operativos, capas para aplicaciones, escudo para certificados y archivo con
llave para licencias. Las plantillas globales y propias de compañía permiten elegir,
diff --git a/modules/assets/src/web/catalog/shared/catalog.test.tsx b/modules/assets/src/web/catalog/shared/catalog.test.tsx
index cde3ece..3074a54 100644
--- a/modules/assets/src/web/catalog/shared/catalog.test.tsx
+++ b/modules/assets/src/web/catalog/shared/catalog.test.tsx
@@ -109,6 +109,6 @@ test("las plantillas ofrecen selección visual traducida y conservan el icono al
);
assert.ok(empty.includes(none));
- assert.ok(html.includes("lucide-laptop"));
+ assert.ok(html.includes("tabler-icon-device-laptop"));
}
});
diff --git a/modules/resources/src/web/catalog/shared/catalog.test.tsx b/modules/resources/src/web/catalog/shared/catalog.test.tsx
index e061a76..84e9419 100644
--- a/modules/resources/src/web/catalog/shared/catalog.test.tsx
+++ b/modules/resources/src/web/catalog/shared/catalog.test.tsx
@@ -91,15 +91,15 @@ test("iconos de recursos: catálogo y selector traducido conservan la selección
for (const icon of [
"mail",
- "key-round",
+ "key",
"folder",
"headphones",
- "monitor",
- "layers",
+ "device-desktop",
+ "stack-2",
"shield-check",
- "file-key",
+ "file-certificate",
]) {
- assert.ok(list.includes(`lucide-${icon}`));
+ assert.ok(list.includes(`tabler-icon-${icon}`));
}
const empty = await render(
language,
@@ -121,7 +121,7 @@ test("iconos de recursos: catálogo y selector traducido conservan la selección
assert.ok(html.includes(label));
assert.ok(html.includes('role="combobox"'));
assert.ok(html.includes(mail));
- assert.ok(html.includes("lucide-mail"));
+ assert.ok(html.includes("tabler-icon-mail"));
}
}
});
diff --git a/modules/resources/src/web/resources/shared/resources.test.tsx b/modules/resources/src/web/resources/shared/resources.test.tsx
index ab712e0..985ef56 100644
--- a/modules/resources/src/web/resources/shared/resources.test.tsx
+++ b/modules/resources/src/web/resources/shared/resources.test.tsx
@@ -496,7 +496,7 @@ test("recursos: inventario y panel usan el icono vigente de la plantilla sin cam
catalog,
});
- assert.ok(list.includes("lucide-mail"));
+ assert.ok(list.includes("tabler-icon-mail"));
const panel = await render(
"es",
);
- assert.ok(panel.includes("lucide-mail"));
+ assert.ok(panel.includes("tabler-icon-mail"));
const withoutIcon = { ...template, values: { ...template.values, icon: undefined } };
const cleared = await render("es", , {
resources: [resource],
catalog: { items: [withoutIcon] },
});
- assert.equal(cleared.includes("lucide-mail"), false);
+ assert.equal(cleared.includes("tabler-icon-mail"), false);
assert.equal(resource.specification.templateName, source.specification.templateName);
assert.deepEqual(resource.history, source.history);
});
diff --git a/packages/rdx-ui/package.json b/packages/rdx-ui/package.json
index a0a2645..d2e7df2 100644
--- a/packages/rdx-ui/package.json
+++ b/packages/rdx-ui/package.json
@@ -16,10 +16,10 @@
"dependencies": {
"@base-ui/react": "1.8.0",
"@repo/shadcn-ui": "workspace:*",
+ "@tabler/icons-react": "3.49.0",
"@tanstack/react-table": "8.21.3",
"class-variance-authority": "0.7.1",
- "cn": "0.3.0",
- "lucide-react": "1.8.0"
+ "cn": "0.3.0"
},
"devDependencies": {
"@repo/typescript-config": "workspace:*",
diff --git a/packages/rdx-ui/src/components/context-help.tsx b/packages/rdx-ui/src/components/context-help.tsx
index 0c69571..c067a00 100644
--- a/packages/rdx-ui/src/components/context-help.tsx
+++ b/packages/rdx-ui/src/components/context-help.tsx
@@ -1,6 +1,7 @@
-import { ChevronDownIcon, InfoIcon } from "lucide-react";
import type { ReactNode } from "react";
+import { ChevronDownIcon, InfoIcon } from "../lib/icons";
+
export function ContextHelp({
title,
description,
diff --git a/packages/rdx-ui/src/components/entity-list-controls.tsx b/packages/rdx-ui/src/components/entity-list-controls.tsx
index d2fb54b..e26c16e 100644
--- a/packages/rdx-ui/src/components/entity-list-controls.tsx
+++ b/packages/rdx-ui/src/components/entity-list-controls.tsx
@@ -1,9 +1,9 @@
import { Menu } from "@base-ui/react/menu";
import { Button } from "@repo/shadcn-ui/components/button";
-import { EllipsisIcon } from "lucide-react";
import type { ReactNode } from "react";
import { ENTITY_PAGE_SIZES, entityListLabels, entityListPages } from "../lib/entity-list";
+import { EllipsisIcon } from "../lib/icons";
import { SelectWithAction } from "./select-with-action";
diff --git a/packages/rdx-ui/src/components/reorder-handle.tsx b/packages/rdx-ui/src/components/reorder-handle.tsx
index b09f3e6..05d866a 100644
--- a/packages/rdx-ui/src/components/reorder-handle.tsx
+++ b/packages/rdx-ui/src/components/reorder-handle.tsx
@@ -1,7 +1,8 @@
import { Button } from "@repo/shadcn-ui/components/button";
-import { GripVerticalIcon } from "lucide-react";
import type { ComponentProps } from "react";
+import { GripVerticalIcon } from "../lib/icons";
+
/** Asa con nombre traducido; el consumidor aporta los eventos de arrastre y teclado. */
export function ReorderHandle({
label,
diff --git a/packages/rdx-ui/src/components/select-with-action.tsx b/packages/rdx-ui/src/components/select-with-action.tsx
index 02f2975..dd6662d 100644
--- a/packages/rdx-ui/src/components/select-with-action.tsx
+++ b/packages/rdx-ui/src/components/select-with-action.tsx
@@ -6,7 +6,8 @@ import {
SelectTrigger,
SelectValue,
} from "@repo/shadcn-ui/components/select";
-import { PlusIcon } from "lucide-react";
+
+import { PlusIcon } from "../lib/icons";
import { ButtonGroup } from "./button-group";
diff --git a/packages/rdx-ui/src/components/template-section-editor.tsx b/packages/rdx-ui/src/components/template-section-editor.tsx
index 77fad12..5a8691f 100644
--- a/packages/rdx-ui/src/components/template-section-editor.tsx
+++ b/packages/rdx-ui/src/components/template-section-editor.tsx
@@ -6,11 +6,12 @@ import {
} from "@repo/shadcn-ui/components/collapsible";
import { Input } from "@repo/shadcn-ui/components/input";
import { Textarea } from "@repo/shadcn-ui/components/textarea";
-import { ArrowDownIcon, ArrowUpIcon, ChevronRightIcon, Trash2Icon } from "lucide-react";
import type { ReactNode } from "react";
import { useId, useState } from "react";
import { flushSync } from "react-dom";
+import { ArrowDownIcon, ArrowUpIcon, ChevronRightIcon, Trash2Icon } from "../lib/icons";
+
import type { FieldSection } from "./field-sections";
import { FormLabel } from "./form-label";
import type { SectionEditorLabels } from "./template-sections-editor";
diff --git a/packages/rdx-ui/src/components/template-section-fields.tsx b/packages/rdx-ui/src/components/template-section-fields.tsx
index fd70e55..f398cb3 100644
--- a/packages/rdx-ui/src/components/template-section-fields.tsx
+++ b/packages/rdx-ui/src/components/template-section-fields.tsx
@@ -1,8 +1,8 @@
import { Button } from "@repo/shadcn-ui/components/button";
-import { ArrowDownIcon, ArrowUpIcon, PlusIcon, Trash2Icon } from "lucide-react";
import { useId } from "react";
import { useDragReorder } from "../hooks/use-drag-reorder";
+import { ArrowDownIcon, ArrowUpIcon, PlusIcon, Trash2Icon } from "../lib/icons";
import type { FieldSection } from "./field-sections";
import { FormLabel } from "./form-label";
diff --git a/packages/rdx-ui/src/components/template-sections-editor.tsx b/packages/rdx-ui/src/components/template-sections-editor.tsx
index 1493f35..b12d26d 100644
--- a/packages/rdx-ui/src/components/template-sections-editor.tsx
+++ b/packages/rdx-ui/src/components/template-sections-editor.tsx
@@ -1,8 +1,8 @@
import { Button } from "@repo/shadcn-ui/components/button";
-import { PlusIcon } from "lucide-react";
import { useId } from "react";
import { useDragReorder } from "../hooks/use-drag-reorder";
+import { PlusIcon } from "../lib/icons";
import { removeTemplateSection } from "../lib/template-sections";
import type { FieldSection } from "./field-sections";
diff --git a/packages/rdx-ui/src/lib/icons.ts b/packages/rdx-ui/src/lib/icons.ts
index d5f5bb7..db6bf4b 100644
--- a/packages/rdx-ui/src/lib/icons.ts
+++ b/packages/rdx-ui/src/lib/icons.ts
@@ -1,45 +1,53 @@
+/** Catálogo visual propio: nombres semánticos estables y componentes SVG de Tabler. */
export {
- BatteryChargingIcon,
- BellIcon,
- BoxIcon,
- BriefcaseIcon,
- Building2Icon,
- CameraIcon,
- ChevronDownIcon,
- ChevronLeftIcon,
- ChevronRightIcon,
- ClockIcon,
- DatabaseIcon,
- FileKeyIcon,
- FolderIcon,
- HardDriveIcon,
- HeadphonesIcon,
- HomeIcon,
- KeyRoundIcon,
- KeyboardIcon,
- LaptopIcon,
- LayersIcon,
- LayoutTemplateIcon,
- MailIcon,
- MapPinIcon,
- MonitorCogIcon,
- MonitorIcon,
- MouseIcon,
- NetworkIcon,
- PhoneIcon,
- PrinterIcon,
- RouterIcon,
- SearchIcon,
- ServerIcon,
- SettingsIcon,
- ShieldCheckIcon,
- SmartphoneIcon,
- TabletIcon,
- TicketIcon,
- TriangleAlertIcon,
- UserRoundXIcon,
- UsersIcon,
- WifiIcon,
- WrenchIcon,
- XIcon,
-} from "lucide-react";
+ IconAlertTriangle as TriangleAlertIcon,
+ IconArrowDown as ArrowDownIcon,
+ IconArrowUp as ArrowUpIcon,
+ IconBatteryCharging as BatteryChargingIcon,
+ IconBell as BellIcon,
+ IconBox as BoxIcon,
+ IconBriefcase as BriefcaseIcon,
+ IconBuildings as Building2Icon,
+ IconCamera as CameraIcon,
+ IconChevronDown as ChevronDownIcon,
+ IconChevronLeft as ChevronLeftIcon,
+ IconChevronRight as ChevronRightIcon,
+ IconClock as ClockIcon,
+ IconDatabase as DatabaseIcon,
+ IconDeviceDesktop as MonitorIcon,
+ IconDeviceDesktopCog as MonitorCogIcon,
+ IconDeviceLaptop as LaptopIcon,
+ IconDeviceMobile as SmartphoneIcon,
+ IconDeviceTablet as TabletIcon,
+ IconDots as EllipsisIcon,
+ IconFileCertificate as FileKeyIcon,
+ IconFolder as FolderIcon,
+ IconGripVertical as GripVerticalIcon,
+ IconHeadphones as HeadphonesIcon,
+ IconHome as HomeIcon,
+ IconInfoCircle as InfoIcon,
+ IconKey as KeyRoundIcon,
+ IconKeyboard as KeyboardIcon,
+ IconLayoutDashboard as LayoutTemplateIcon,
+ IconMail as MailIcon,
+ IconMapPin as MapPinIcon,
+ IconMouse as MouseIcon,
+ IconPhone as PhoneIcon,
+ IconPlus as PlusIcon,
+ IconPrinter as PrinterIcon,
+ IconRouter as RouterIcon,
+ IconSearch as SearchIcon,
+ IconServer as ServerIcon,
+ IconServer2 as HardDriveIcon,
+ IconSettings as SettingsIcon,
+ IconShieldCheck as ShieldCheckIcon,
+ IconSitemap as NetworkIcon,
+ IconStack2 as LayersIcon,
+ IconTicket as TicketIcon,
+ IconTool as WrenchIcon,
+ IconTrash as Trash2Icon,
+ IconUserX as UserRoundXIcon,
+ IconUsers as UsersIcon,
+ IconWifi as WifiIcon,
+ IconX as XIcon,
+} from "@tabler/icons-react";
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ae12a58..d087979 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -493,6 +493,9 @@ importers:
'@repo/shadcn-ui':
specifier: workspace:*
version: link:../shadcn-ui
+ '@tabler/icons-react':
+ specifier: 3.49.0
+ version: 3.49.0(react@19.2.5)
'@tanstack/react-table':
specifier: 8.21.3
version: 8.21.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
@@ -502,9 +505,6 @@ importers:
cn:
specifier: 0.3.0
version: 0.3.0
- lucide-react:
- specifier: 1.8.0
- version: 1.8.0(react@19.2.5)
devDependencies:
'@repo/typescript-config':
specifier: workspace:*
@@ -1733,6 +1733,14 @@ packages:
peerDependencies:
eslint: ^9.0.0 || ^10.0.0
+ '@tabler/icons-react@3.49.0':
+ resolution: {integrity: sha512-Um59pm5RVNUaQjFUtG0r4oYJbZuBS3tGugAA2tgBg0WufMk34Eio3nsO30RUkLuL2giYPQUNdY9HvqltLLYyNA==}
+ peerDependencies:
+ react: '>= 16'
+
+ '@tabler/icons@3.49.0':
+ resolution: {integrity: sha512-l+GnSkFETx0U26icxv1VUFnxxiTqXfCcVRiRAnyMwibupM2S2L/hSaZ9gmSgz01rkrsH/93NvLsxykqdanc6lw==}
+
'@tailwindcss/node@4.2.2':
resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==}
@@ -5120,6 +5128,13 @@ snapshots:
estraverse: 5.3.0
picomatch: 4.0.7
+ '@tabler/icons-react@3.49.0(react@19.2.5)':
+ dependencies:
+ '@tabler/icons': 3.49.0
+ react: 19.2.5
+
+ '@tabler/icons@3.49.0': {}
+
'@tailwindcss/node@4.2.2':
dependencies:
'@jridgewell/remapping': 2.3.5