diff --git a/apps/web/src/global.css b/apps/web/src/global.css
index 5411e88..bc98082 100644
--- a/apps/web/src/global.css
+++ b/apps/web/src/global.css
@@ -58,3 +58,28 @@
--spacing-shell-avatar: 35px;
--shadow-shell-popover: 0 3px 12px rgb(12 40 80 / 8%);
}
+
+/* Enlaces de contenido y controles que navegan: criterio común en toda la aplicación. */
+@layer components {
+ .app-link {
+ color: var(--primary);
+ cursor: pointer;
+ text-underline-offset: 4px;
+ }
+
+ .app-link:hover {
+ text-decoration-line: underline;
+ }
+
+ .app-link:focus-visible {
+ outline: 2px solid var(--ring);
+ outline-offset: 3px;
+ }
+
+ .app-link:disabled,
+ .app-link[data-disabled],
+ .app-link[aria-disabled="true"] {
+ cursor: default;
+ text-decoration-line: none;
+ }
+}
diff --git a/docs/componentes-de-interfaz.md b/docs/componentes-de-interfaz.md
index fefe15f..d5b454c 100644
--- a/docs/componentes-de-interfaz.md
+++ b/docs/componentes-de-interfaz.md
@@ -309,3 +309,9 @@ Las secciones de consulta evitan recuadros anidados y rellenos laterales: usan t
`DetailSection` ofrece agrupación plegable nativa (`details/summary`), abierta inicialmente, accesible por teclado. `DetailField` devuelve una fila semántica `dt/dd` para incluir en un `dl`: etiqueta y valor se alinean horizontalmente cuando el contenedor dispone de al menos 240 px y se apilan en espacios menores. El consumidor aporta los enlaces; el componente común les aplica cursor de enlace, color semántico y subrayado al pasar el puntero. Los valores ausentes permanecen como texto.
La ficha lateral de activos utiliza un ancho adaptable entre 320 y 400 px, acciones debajo del título y bloques de identificación, ubicación/asignación, características, observaciones, relaciones y asistencia. Conserva las secciones capturadas de la plantilla, incluyendo la compatibilidad con especificaciones antiguas sin agrupación; no modifica valores ni instantáneas. Las relaciones llevan a destinos existentes: persona y activo relacionado a su ficha; sede, puesto y plantilla a sus listados/catálogos actuales. La vista completa e historial mantienen sus funciones. Las fichas de recursos reutilizan las filas de características. No se crean nuevas fichas laterales ni nuevas rutas.
+
+## Enlaces y controles de navegación
+
+Los enlaces de contenido usan `app-link`: color semántico `primary`, cursor de mano, subrayado al pasar el puntero y foco visible por teclado. `BrowserLink` lo incorpora de forma predeterminada, conservando la navegación interna, los clics modificados, destinos externos y descargas. Los botones que presentan nombres navegables o «Ver todos» comparten este estilo sin alterar sus callbacks. Los controles deshabilitados no muestran cursor de enlace ni subrayado. La navegación lateral y los enlaces presentados como botones conservan los colores de su contexto para mantener contraste; las acciones de guardar, editar o cancelar mantienen su presentación de botón.
+
+En el menú de secciones de una compañía, los elementos utilizan el color normal de texto y solo destacan su texto al pasar el puntero. Se mantienen el cursor de mano, el foco por teclado y el indicador de la sección actual. Esta excepción no afecta a enlaces dentro de listados, fichas o bloques del dashboard.
diff --git a/modules/assets/src/web/asset-relationships/list/ui/asset-relationships.tsx b/modules/assets/src/web/asset-relationships/list/ui/asset-relationships.tsx
index 949bd72..392636d 100644
--- a/modules/assets/src/web/asset-relationships/list/ui/asset-relationships.tsx
+++ b/modules/assets/src/web/asset-relationships/list/ui/asset-relationships.tsx
@@ -22,7 +22,7 @@ export function AssetRelationships(props: AssetRelationshipsProps) {
{source ? link.values.name : link.values.inverseName} ·{" "}
{nameOf(source ? link.values.targetId : link.values.sourceId)}
diff --git a/modules/assets/src/web/assets/list/ui/inventory-page.tsx b/modules/assets/src/web/assets/list/ui/inventory-page.tsx
index 3bf697d..f2e80ed 100644
--- a/modules/assets/src/web/assets/list/ui/inventory-page.tsx
+++ b/modules/assets/src/web/assets/list/ui/inventory-page.tsx
@@ -100,7 +100,7 @@ export function AssetInventoryPage(props: AssetInventoryPageProps) {
render: (asset) => (
setDetailOpen(true)}
>
diff --git a/modules/assets/src/web/catalog/shared/ui/catalog-name.tsx b/modules/assets/src/web/catalog/shared/ui/catalog-name.tsx
index fcac15d..07e0743 100644
--- a/modules/assets/src/web/catalog/shared/ui/catalog-name.tsx
+++ b/modules/assets/src/web/catalog/shared/ui/catalog-name.tsx
@@ -21,7 +21,7 @@ export function CatalogName({
return (
<>
diff --git a/modules/assets/src/web/workstations/list/ui/workstations-page.tsx b/modules/assets/src/web/workstations/list/ui/workstations-page.tsx
index 089aa58..98e14d7 100644
--- a/modules/assets/src/web/workstations/list/ui/workstations-page.tsx
+++ b/modules/assets/src/web/workstations/list/ui/workstations-page.tsx
@@ -68,7 +68,7 @@ export function WorkstationsPage(props: WorkstationsPageProps) {
hideable: false,
render: (item) => (
setView(item.id)}
type="button"
>
diff --git a/modules/companies/src/web/application-configurations/list/ui/application-configurations-page.tsx b/modules/companies/src/web/application-configurations/list/ui/application-configurations-page.tsx
index 15b8aae..bdf8d04 100644
--- a/modules/companies/src/web/application-configurations/list/ui/application-configurations-page.tsx
+++ b/modules/companies/src/web/application-configurations/list/ui/application-configurations-page.tsx
@@ -80,7 +80,7 @@ export function ApplicationConfigurationsPage(props: ApplicationConfigurationsPa
hideable: false,
render: (item) => (
setView(item.id)}
type="button"
>
diff --git a/modules/companies/src/web/certificate-configurations/list/ui/certificate-configurations-page.tsx b/modules/companies/src/web/certificate-configurations/list/ui/certificate-configurations-page.tsx
index 231aa60..d4ff698 100644
--- a/modules/companies/src/web/certificate-configurations/list/ui/certificate-configurations-page.tsx
+++ b/modules/companies/src/web/certificate-configurations/list/ui/certificate-configurations-page.tsx
@@ -80,7 +80,7 @@ export function CertificateConfigurationsPage(props: CertificateConfigurationsPa
hideable: false,
render: (item) => (
setView(item.id)}
type="button"
>
diff --git a/modules/companies/src/web/companies/detail/ui/company-detail.tsx b/modules/companies/src/web/companies/detail/ui/company-detail.tsx
index 6d1c644..487593e 100644
--- a/modules/companies/src/web/companies/detail/ui/company-detail.tsx
+++ b/modules/companies/src/web/companies/detail/ui/company-detail.tsx
@@ -158,8 +158,8 @@ export function CompanyDetail(props: CompanyDetailProps) {
aria-pressed={tab === section}
className={
embedded
- ? "h-auto min-h-10 w-full justify-start whitespace-normal text-left text-[13px] leading-[1.4285714286] aria-pressed:bg-accent aria-pressed:hover:bg-accent dark:aria-pressed:hover:bg-accent aria-pressed:text-accent-foreground shell:text-sm"
- : undefined
+ ? "cursor-pointer text-foreground hover:text-primary h-auto min-h-10 w-full justify-start whitespace-normal text-left text-[13px] leading-[1.4285714286] aria-pressed:bg-accent aria-pressed:hover:bg-accent dark:aria-pressed:hover:bg-accent aria-pressed:text-accent-foreground shell:text-sm"
+ : "cursor-pointer text-foreground hover:text-primary"
}
{...(props.onSectionChange
? {
diff --git a/modules/companies/src/web/companies/list/ui/companies-page.tsx b/modules/companies/src/web/companies/list/ui/companies-page.tsx
index c0a43cd..b355819 100644
--- a/modules/companies/src/web/companies/list/ui/companies-page.tsx
+++ b/modules/companies/src/web/companies/list/ui/companies-page.tsx
@@ -85,7 +85,7 @@ export function CompaniesPage(props: CompaniesPageProps) {
hideable: false,
render: (company) => (
{action && (
-
+
{t("dashboard.viewAll")}
diff --git a/modules/companies/src/web/folder-mappings/list/ui/folder-mappings-page.tsx b/modules/companies/src/web/folder-mappings/list/ui/folder-mappings-page.tsx
index 844bbc2..bca9d05 100644
--- a/modules/companies/src/web/folder-mappings/list/ui/folder-mappings-page.tsx
+++ b/modules/companies/src/web/folder-mappings/list/ui/folder-mappings-page.tsx
@@ -73,7 +73,7 @@ export function FolderMappingsPage(props: FolderMappingsPageProps) {
hideable: false,
render: (item) => (
setView(item.id)}
type="button"
>
diff --git a/modules/companies/src/web/interventions/list/ui/interventions-page.tsx b/modules/companies/src/web/interventions/list/ui/interventions-page.tsx
index b20ca30..4ed194f 100644
--- a/modules/companies/src/web/interventions/list/ui/interventions-page.tsx
+++ b/modules/companies/src/web/interventions/list/ui/interventions-page.tsx
@@ -84,7 +84,7 @@ export function InterventionsPage(props: InterventionsPageProps) {
hideable: false,
render: (intervention) => (
{intervention.reference}
@@ -98,7 +98,7 @@ export function InterventionsPage(props: InterventionsPageProps) {
hideable: false,
render: (intervention) => (
{intervention.values.subject}
diff --git a/modules/companies/src/web/mail-configurations/list/ui/mail-configurations-page.tsx b/modules/companies/src/web/mail-configurations/list/ui/mail-configurations-page.tsx
index 344ce46..1888195 100644
--- a/modules/companies/src/web/mail-configurations/list/ui/mail-configurations-page.tsx
+++ b/modules/companies/src/web/mail-configurations/list/ui/mail-configurations-page.tsx
@@ -79,7 +79,7 @@ export function MailConfigurationsPage(props: MailConfigurationsPageProps) {
hideable: false,
render: (item) => (
setView(item.id)}
type="button"
>
diff --git a/modules/companies/src/web/people/list/ui/people-section.tsx b/modules/companies/src/web/people/list/ui/people-section.tsx
index 1657401..80e6955 100644
--- a/modules/companies/src/web/people/list/ui/people-section.tsx
+++ b/modules/companies/src/web/people/list/ui/people-section.tsx
@@ -104,7 +104,7 @@ export function PeopleSection({
render: (person) => (
<>
{person.name}
diff --git a/modules/companies/src/web/printer-configurations/list/ui/printer-configurations-page.tsx b/modules/companies/src/web/printer-configurations/list/ui/printer-configurations-page.tsx
index 5108485..8180e61 100644
--- a/modules/companies/src/web/printer-configurations/list/ui/printer-configurations-page.tsx
+++ b/modules/companies/src/web/printer-configurations/list/ui/printer-configurations-page.tsx
@@ -74,7 +74,7 @@ export function PrinterConfigurationsPage(props: PrinterConfigurationsPageProps)
hideable: false,
render: (item) => (
setView(item.id)}
type="button"
>
diff --git a/modules/companies/src/web/processes/list/ui/processes-page.tsx b/modules/companies/src/web/processes/list/ui/processes-page.tsx
index 6632a48..cac5602 100644
--- a/modules/companies/src/web/processes/list/ui/processes-page.tsx
+++ b/modules/companies/src/web/processes/list/ui/processes-page.tsx
@@ -96,7 +96,7 @@ export function ProcessesPage(props: ProcessesPageProps) {
hideable: false,
render: (p) => (
{p.values.name}
diff --git a/modules/companies/src/web/remote-connections/list/ui/remote-connections-page.tsx b/modules/companies/src/web/remote-connections/list/ui/remote-connections-page.tsx
index 593bcb5..4ea2728 100644
--- a/modules/companies/src/web/remote-connections/list/ui/remote-connections-page.tsx
+++ b/modules/companies/src/web/remote-connections/list/ui/remote-connections-page.tsx
@@ -77,7 +77,7 @@ export function RemoteConnectionsPage(props: RemoteConnectionsPageProps) {
hideable: false,
render: (c) => (
setView(c.id)}
type="button"
>
diff --git a/modules/companies/src/web/telework-authorizations/list/ui/telework-authorizations-page.tsx b/modules/companies/src/web/telework-authorizations/list/ui/telework-authorizations-page.tsx
index 3f7b000..8774765 100644
--- a/modules/companies/src/web/telework-authorizations/list/ui/telework-authorizations-page.tsx
+++ b/modules/companies/src/web/telework-authorizations/list/ui/telework-authorizations-page.tsx
@@ -77,7 +77,7 @@ export function TeleworkAuthorizationsPage(props: TeleworkAuthorizationsPageProp
hideable: false,
render: (item) => (
setView(item.id)}
type="button"
>
diff --git a/modules/companies/src/web/tickets/list/ui/tickets-page.tsx b/modules/companies/src/web/tickets/list/ui/tickets-page.tsx
index aace4cb..4fc5cd5 100644
--- a/modules/companies/src/web/tickets/list/ui/tickets-page.tsx
+++ b/modules/companies/src/web/tickets/list/ui/tickets-page.tsx
@@ -87,7 +87,7 @@ export function TicketsPage(props: TicketsPageProps) {
hideable: false,
render: (ticket) => (
{ticket.reference}
@@ -101,7 +101,7 @@ export function TicketsPage(props: TicketsPageProps) {
hideable: false,
render: (ticket) => (
{ticket.values.subject}
diff --git a/modules/companies/src/web/work-profiles/list/ui/work-profiles-page.tsx b/modules/companies/src/web/work-profiles/list/ui/work-profiles-page.tsx
index 9257c37..6535502 100644
--- a/modules/companies/src/web/work-profiles/list/ui/work-profiles-page.tsx
+++ b/modules/companies/src/web/work-profiles/list/ui/work-profiles-page.tsx
@@ -98,7 +98,7 @@ export function WorkProfilesPage(props: WorkProfilesPageProps) {
hideable: false,
render: (item) => (
{item.values.name}
diff --git a/modules/companies/src/web/workspace/shared/ui/route-feedback.tsx b/modules/companies/src/web/workspace/shared/ui/route-feedback.tsx
index 377103c..35000ff 100644
--- a/modules/companies/src/web/workspace/shared/ui/route-feedback.tsx
+++ b/modules/companies/src/web/workspace/shared/ui/route-feedback.tsx
@@ -9,9 +9,7 @@ export function RouteFeedback({ invalid = false }: { invalid?: boolean }) {
{t(invalid ? "navigation.invalidRoute" : "navigation.notFound")}
{t("navigation.routeHelp")}
-
- {t("dashboard.title")}
-
+ {t("dashboard.title")}
);
}
diff --git a/modules/core/src/web/navigation/shared/ui/browser-link.tsx b/modules/core/src/web/navigation/shared/ui/browser-link.tsx
index dd518e7..0576edf 100644
--- a/modules/core/src/web/navigation/shared/ui/browser-link.tsx
+++ b/modules/core/src/web/navigation/shared/ui/browser-link.tsx
@@ -2,10 +2,16 @@ import type { ComponentProps } from "react";
import { isInternalPath, navigateTo } from "../helpers/browser-navigation";
-export function BrowserLink({ href, onClick, ...props }: ComponentProps<"a"> & { href: string }) {
+export function BrowserLink({
+ href,
+ onClick,
+ className,
+ ...props
+}: ComponentProps<"a"> & { href: string }) {
return (
{
onClick?.(event);
diff --git a/modules/identity/src/web/workspace/view/ui/custom-workspace.tsx b/modules/identity/src/web/workspace/view/ui/custom-workspace.tsx
index 47fe438..0ad25cd 100644
--- a/modules/identity/src/web/workspace/view/ui/custom-workspace.tsx
+++ b/modules/identity/src/web/workspace/view/ui/custom-workspace.tsx
@@ -33,9 +33,7 @@ export function CustomWorkspace({
return (
{t("errors.FORBIDDEN")}
-
- {t("workspace")}
-
+ {t("workspace")}
);
}
diff --git a/modules/resources/src/web/catalog/shared/ui/catalog-name.tsx b/modules/resources/src/web/catalog/shared/ui/catalog-name.tsx
index 639421a..19b6ae1 100644
--- a/modules/resources/src/web/catalog/shared/ui/catalog-name.tsx
+++ b/modules/resources/src/web/catalog/shared/ui/catalog-name.tsx
@@ -21,7 +21,7 @@ export function CatalogName({
return (
<>
diff --git a/modules/resources/src/web/resources/list/ui/resources-page.tsx b/modules/resources/src/web/resources/list/ui/resources-page.tsx
index 099115f..9b4937b 100644
--- a/modules/resources/src/web/resources/list/ui/resources-page.tsx
+++ b/modules/resources/src/web/resources/list/ui/resources-page.tsx
@@ -72,7 +72,7 @@ export function ResourcesPage(props: ResourcesPageProps) {
hideable: false,
render: (item) => (
{item.values.name}