Files
project.linkedcorp.net/docs/UI-UX-WINDOWS.md
T
Milton Gonzalez 1e6e7fecdd fix(ui): reemplaza panel-debajo-del-listado por DetailPopup de tamaño fijo
El detalle de un item de listado (actividad, departamento, usuario, proyecto nuevo,
catalogo) ya no se apila debajo ni al costado del listado: ahora abre en un popup que
cubre la ventana, deja el listado inactivo detras, nunca se cierra con clic afuera (solo
con el boton Cerrar o una accion explicita del formulario) y mantiene un alto FIJO por
instancia para que cambiar de pestaña interna (Info/Subtareas/Dependencias/Comentarios/
Documentos) no reajuste su tamaño.

De paso corrige un bug real de stacking: ContentDialog no usaba portal a document.body,
así que un dialogo de confirmacion abierto desde dentro de un DetailPopup quedaba oculto
detras de este. Ahora ambos son portales con una jerarquia de z-index explicita
(Flyout 100 < DetailPopup 200 < ContentDialog 250 < Toast 300).

En el detalle de actividad, Subtareas y Dependencias pasan de estar apiladas dentro de la
pestaña Info a ser cada una su propia pestaña.

Regla documentada en project-md-templates/UI-UX-WINDOWS.md (componente DetailPopup) para
que aplique a futuros proyectos de escritorio Windows del grupo.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 11:21:07 -05:00

23 KiB
Raw Blame History

UI/UX — Identidad para aplicaciones de escritorio Windows (cómo construir pantallas)

🖥️ Muestra viva: UI-UX-WINDOWS.html (en esta misma carpeta) — ábrela en el navegador para VER todos los elementos (ventana con barra de título propia, panel de navegación, comandos, listado con clic derecho, maestro-detalle, diálogos, flyouts, configuración). Es lo primero que se le muestra al usuario al arrancar un proyecto de escritorio Windows para que apruebe o pida ajustes de la identidad antes de construir. Usa dos JS locales junto al HTML (sin CDN, offline): lucide.min.js (íconos) y chart.umd.js (gráficas Chart.js) — cópialos junto al HTML si se mueve.

⚠️ Este documento es la referencia visual y de interacción (look & feel, tokens, componentes, nomenclatura de regiones). No asume una tecnología de implementación concreta: sirve tanto para una app WinUI 3/.NET nativa como para una app Electron/Tauri, o cualquier otro stack de escritorio Windows. Cada proyecto decide su stack al copiar este documento; lo que no cambia es el comportamiento y la identidad descritos aquí — son los que hacen que la app "se sienta Windows".

Estilo de referencia: Fluent Design / Windows 11 (Mica, esquinas redondeadas, tipografía Segoe UI Variable, paleta de acento del sistema). Pensado primero para mouse (hover, clic derecho, arrastre), sin dejar de ser accesible por teclado.


1. Identidad visual (tokens y tema)

Colores como variables CSS RGB (o el equivalente del framework elegido: DynamicResource en WPF/WinUI, CSS vars en Electron/Tauri), para poder escribir rgb(var(--accent)/.2) y variantes con transparencia. Tema oscuro por defecto + claro vía data-theme="light".

Token Uso Oscuro (ref.) Claro (ref.)
canvas fondo de ventana (equivalente a Mica) 32 32 32 243 243 243
surface tarjetas, diálogos, flyouts 43 43 43 255 255 255
panel panel de navegación, hover de filas 51 51 51 249 249 249
field fondo de campos de entrada 43 43 43 255 255 255
body texto principal 255 255 255 32 32 32
muted texto secundario, labels, hints 168 168 168 96 96 96
line bordes y divisores 70 70 70 225 225 225
accent acción primaria — el acento del sistema 0 120 212 0 103 192
success / warning / danger estados 108 203 95 / 255 185 0 / 255 105 97 16 124 16 / 157 93 0 / 196 43 28

Acento del sistema (do & don't): Windows deja al usuario elegir un color de acento en la configuración del sistema; la app debe heredarlo cuando el framework lo expone (WinUI 3 lo hace automático vía AccentColor), o dar un selector propio con la paleta estándar si no hay acceso al acento del SO. Paleta de referencia (la que usa la muestra viva): blue #0078D4 (por defecto), purple #8764B8, green #10893E, red #C42B1C, orange #CA5010, teal #009984.

Tipografía: Segoe UI Variable (Windows 11) como fuente del sistema — no requiere carga de fuente web, ya está instalada en Windows: font-family:'Segoe UI Variable Text','Segoe UI',system-ui,sans-serif. Los títulos grandes usan el corte Display de la misma familia (Segoe UI Variable Display). Escala: .72rem metadatos/labels · .8–.82rem cuerpo/controles · 1.05–1.25rem títulos de sección · 1.6rem+ valores KPI/Display. Pesos: 600–700 títulos y labels, 400 párrafos.

Forma (radios de Fluent 2): --r-sm: 4px en controles (botones, campos, checkboxes) y --r-lg: 8px en superficies elevadas (tarjetas, diálogos, flyouts, menús, y la propia ventana). No usar esquinas totalmente cuadradas ni "pill" (999px) salvo en ToggleSwitch, badge y avatar.

Iconografía: un solo set en toda la app. Dos opciones válidas:

  • Lucide (la que usa la muestra viva, lucide.min.js local) — mismo estándar que ya usa el grupo en sus apps web (UI-UX-LINKEDCORP.md), da continuidad visual entre plataformas y permite compartir nombres de ícono entre el proyecto web y el de escritorio de un mismo cliente.
  • Segoe Fluent Icons (fuente de glifos del propio Windows) — 100% nativo, cero peso adicional, pero solo tiene sentido en una implementación WinUI/WPF nativa (no está disponible como webfont fuera de Windows).
  • Los íconos heredan el color del contexto (activo = accent, texto = body/muted). No mezclar ambos sets en la misma app.

2. Mensajes del sistema — jerarquía de avisos (REGLA DE ORO)

A diferencia de la web (donde todo pasa por un único AppDialog), una app de escritorio Windows tiene cuatro mecanismos de aviso, cada uno con un propósito distinto. Elegir el correcto es parte de la identidad:

Mecanismo Para qué Bloquea Ejemplo
ContentDialog (modal) toda decisión del usuario (confirmar, elegir, error crítico) Sí "¿Eliminar el cliente CLI-002?"
InfoBar estado o aviso no bloqueante, embebido en el contenido de la pantalla No "Sincronización activa", "Licencia por vencer"
Toast/notificación evento de fondo, sin interacción esperada, autodesaparece No "Copia de seguridad completada"
Flyout acción o info contextual, anclada a un control, se cierra al hacer clic fuera No (light-dismiss) menú de usuario, "¿seguro?" ligado a un botón puntual

Nunca MessageBox/alert/confirm del sistema operativo ni del navegador si el shell es web-based: siempre el ContentDialog propio, para mantener consistencia visual entre Windows y el resto de plataformas del grupo.

Contrato del ContentDialog (equivalente al openDialog del template web):

openDialog({
  tone: 'info' | 'success' | 'warning' | 'error',   // franja superior + color del ícono/título
  title: 'Título claro',
  message: 'Descripción en lenguaje del usuario',
  actions: [                                          // opcional; sin actions -> botón "Cerrar"
    { label: 'Cancelar', variant: 'standard' },
    { label: 'Eliminar', variant: 'danger', onClick: async () => { ... }, keepOpen: false },
  ],
});
  • Sin actions ⇒ botón "Cerrar" (accent) automático. keepOpen: true mantiene el diálogo abierto tras el onClick (procesos largos).
  • Sets de botones estándar (misma convención que la identidad web): Aceptar/Cancelar, Sí/No, Eliminar(danger)/Cancelar, Guardar/Descartar. Acción primaria a la derecha, Cancelar/No a la izquierda. Los botones de decisión siempre muestran texto (nunca solo ícono).
  • El ContentDialog se centra sobre la ventana de la app, no sobre toda la pantalla del monitor.

3. Kit de componentes (resumen; ver el markup/CSS de referencia en UI-UX-WINDOWS.html)

  • Botones — accent (relleno de color, acción primaria), standard (borde + fondo neutro), subtle (transparente, solo hover), danger (borde/texto rojo). Alto 32px (sm 26px). Todo botón compone ícono (izq.) + texto; en toolbars muy densas puede ir solo ícono con tooltip obligatorio indicando la acción.
  • Campos — TextBox, NumberBox (con spinner +/-), ComboBox propio (desplegable redondeado, con buscador si la lista tiene ≥10 ítems; nunca el <select>/combo nativo del SO — no se puede redondear ni estilar), Textarea, CheckBox, RadioButtons, ToggleSwitch (interruptor), Slider.
  • DatePicker/TimePicker — calendario propio en un flyout anclado al campo (navegación de mes, día de hoy marcado, selección resaltada con accent); igual criterio que ComboBox: no usar el selector nativo del SO por falta de control visual.
  • ListView/DataGrid — tabla con encabezados ordenables (clic ordena asc/desc), columna de selección múltiple (checkbox), fila con hover y estado seleccionado (accent/.14), y clic derecho que abre el menú contextual de esa fila (ver §6). Alternativa por fila sin mouse derecho: botón ⋯ que abre el mismo menú.
  • DetailPopup — patrón por defecto para ver/crear/editar el detalle de un ítem de un listado de gestión (proyectos, actividades, usuarios, catálogos, etc.). Overlay que cubre la ventana y deja inactivo el listado detrás (dim + sin interacción) mientras se usa el popup — a diferencia de un panel lateral o de un panel apilado debajo del listado, el detalle NUNCA reduce ni empuja el listado, y siempre aparece completo y en el mismo lugar sin importar el largo de la lista ni la fila elegida. Reglas duras:
    • Nunca se cierra con clic afuera (a diferencia de Flyout) — solo con el botón "Cerrar" de su cabecera o una acción explícita del formulario (Guardar/Cancelar).
    • Alto FIJO por instancia, no se ajusta al contenido: si el popup tiene pestañas o secciones internas (p. ej. Info/Comentarios/Documentos), cambiar entre ellas nunca cambia el tamaño del popup — solo el contenido interno hace scroll. El ancho/alto se elige según cuánto contenido espera esa pantalla (un formulario simple de 2 campos no necesita el mismo alto que un detalle con subtareas y dependencias), pero una vez abierto queda fijo.
    • Header propio: título a la izquierda, botón "Cerrar" (ícono X) a la derecha.
    • Contrato (React; adaptar al framework del proyecto): <DetailPopup open title onClose width height>{contenido}</DetailPopup> — portal a document.body (igual que Flyout/ContentDialog), nunca anidado dentro del árbol de la página, para no quedar atrapado en el stacking context de un ancestro y terminar tapado por otro overlay (bug real: sin portal, un ContentDialog abierto DESDE un DetailPopup quedaba oculto detrás de este). Jerarquía de z-index entre overlays: Flyout (100) < DetailPopup (200) < ContentDialog (250) < Toast (300) — así una confirmación abierta desde dentro de un DetailPopup siempre queda por encima.
    • Secciones internas relacionadas con el ítem (ej. una actividad con Info + Subtareas + Dependencias + Comentarios + Documentos) van cada una en su propia pestaña dentro del popup, nunca todas apiladas dentro de la pestaña "Info" — mismo criterio que pestañas reales a nivel de pantalla completa (ver identidad web UI-UX-LINKEDCORP.md), aplicado ahora dentro del popup.
  • Master-Detail (Split View) — patrón nativo de Windows (Correo, Explorador): lista angosta a la izquierda + panel de detalle a la derecha que se actualiza en el sitio al seleccionar un ítem, sin modal. Uso restringido: solo para pantallas cuya función principal es explorar/leer una lista larga como actividad central de esa vista (no para listados de gestión con acciones crear/editar — ahí va DetailPopup). Evitar cualquier variante que ubique el detalle "a un costado" o "debajo" de un listado de gestión (panel lateral fijo, panel acoplado al borde, panel apilado bajo la tabla): en la práctica el detalle se siente secundario y el listado pierde protagonismo o queda "lejos" del detalle cuando la lista crece. Ante la duda entre Master-Detail y DetailPopup para un listado de gestión, usar DetailPopup.
  • Menú contextual (clic derecho) — el patrón de interacción más característico de Windows: ítems con ícono + label + acelerador de teclado a la derecha (Ctrl+E, Del…), separadores, submenú con flecha ▸ que se expande al pasar el mouse, ítem destructivo en danger. Debe estar disponible en toda fila/elemento accionable, no solo en listados.
  • Barra de menú clásica (Archivo · Editar · Ver…) — opcional, solo para apps de productividad/edición que lo necesiten (no todas las apps modernas la llevan; Configuración o Correo no la tienen). Si se usa, cada ítem abre un menú desplegable igual al contextual.
  • Flyout — popover anclado a un control (avatar, botón), con light-dismiss (clic fuera o Esc cierra). Para menús de cuenta, ayuda contextual corta o una confirmación ligada a un botón puntual.
  • InfoBar — banner de 4 tonos (info/success/warning/error) embebido en el contenido, con botón de cierre ✕; no empuja al usuario a decidir, solo informa.
  • Toast — notificación flotante (esquina inferior derecha), autodesaparece (~4s), apilable. Solo para eventos de fondo — si el usuario debe decidir algo, es un ContentDialog, no un toast.
  • Teaching Tip — "coach mark" anclado con flecha, para presentar una función nueva la primera vez (onboarding); se descarta con un botón, no reaparece tras cerrarse.
  • Expander (patrón de Configuración) — fila con ícono + título + descripción + chevron; al hacer clic expande un cuerpo con los controles de esa sección (toggles, botones). Es el patrón estándar para pantallas de Configuración/Ajustes.
  • Treeview — árbol jerárquico estilo Explorador de Windows (▾/▸ para expandir/colapsar, ícono de carpeta/archivo, selección resaltada). Para categorías, carpetas o estructuras anidadas.
  • Barra de título personalizada — reemplaza el chrome nativo de Windows: ícono+nombre de la app a la izquierda (zona arrastrable, mueve la ventana), controles minimizar / maximizar / cerrar a la derecha. Cerrar se resalta en rojo (#C42B1C) al hover; Maximizar muestra, al hover, la vista previa de Snap Layouts (2/3/4 particiones) — detalle que distingue a una app "moderna".
  • NavigationView (panel de navegación) — fijo a la izquierda, con tres modos: expandido (ícono+texto), compacto (solo ícono) y oculto (drawer). Se colapsa con el botón ☰; tiene buscador propio arriba y, al pie, la cuenta del usuario (abre un Flyout).
  • CommandBar — franja de botones de acción de la vista actual (Nuevo, Actualizar, Eliminar…) con botón "···" (overflow) para acciones secundarias cuando no caben todos los botones.
  • BreadcrumbBar — ruta de navegación bajo la barra de comandos, segmentos separados por ›, el último en negrita y no clicable.
  • Barra de estado — pie de ventana con texto pequeño: conteo de elementos/selección, estado de conexión, versión. Equivalente a la barra de estado del Explorador de Windows.
  • KPI / spinner / skeleton / progress bar — igual criterio que en web: tarjetas de indicador con delta ▲/▼, spinner circular para cargas cortas, skeleton para listados, barra de progreso para procesos medibles.
  • Gráficas — Chart.js local (chart.umd.js, sin CDN); colores desde los tokens del tema y se reconstruyen al cambiar tema/acento. maintainAspectRatio:false + contenedor con max-height.
  • Plantillas de ventana — Login (ventana pequeña centrada, avatar, usuario/contraseña, recordarme), Acerca de (ventana utilitaria pequeña con ícono, versión, botón de actualización) y Reporte/factura (documento con Imprimir/Exportar PDF, aislado con @media print si el shell es web-based).

4. Layout (estructura de la ventana) y NOMENCLATURA de regiones

Úsalos para pedir cambios: "cambia X en barra-comandos". La muestra viva rotula visualmente cada región (chip azul) y cada componente (chip verde) al activar el interruptor "Mostrar nombres" (vista Resumen, o menú ··· de la barra de comandos).

Nombre Qué es Comportamiento
ventana contenedor raíz de la app esquinas redondeadas (8px), sombra; simula el marco de una app de escritorio flotando sobre el escritorio
barra-titulo barra de título personalizada arrastrable salvo sobre sus controles; ícono+nombre a la izq., minimizar/maximizar/cerrar a la der.
navegacion panel de navegación izquierdo (NavigationView) FIJO, scroll propio si hay muchos ítems; modos expandido/compacto/oculto
col-derecha columna derecha todo lo no-navegación, alto completo de la ventana
barra-comandos CommandBar de la vista actual botones de acción + overflow ···
migas-pan BreadcrumbBar bajo la barra de comandos; último nivel en negrita
area-contenido contenido de la vista ÚNICA región con scroll propio
panel-detalle panel derecho en vistas maestro-detalle se actualiza al seleccionar un ítem, sin modal
divisor separador arrastrable entre paneles cursor col-resize; el arrastre con mouse redimensiona los paneles adyacentes
barra-estado pie de ventana conteo de ítems/selección, estado; texto pequeño

Comportamiento clave: navegacion queda fija (no se desplaza con area-contenido); solo area-contenido hace scroll. barra-titulo, barra-comandos, migas-pan y barra-estado permanecen siempre visibles.

Ventanas secundarias vs. una sola ventana: a diferencia de la web (todo en una pestaña), una app Windows puede abrir ventanas propias para diálogos de larga duración o utilitarios (Acerca de, Propiedades, un asistente). Regla: usar una ventana secundaria solo cuando el contenido necesita vivir independientemente de la ventana principal (el usuario puede moverla, alternar entre ambas con Alt+Tab); si es una decisión puntual ligada al contexto actual, es un ContentDialog, no una ventana nueva.


5. Interacción — pensada primero para mouse

  • Hover en todo lo accionable: botones, filas de listado, ítems de navegación, ítems de menú y árbol cambian de fondo al pasar el mouse (panel o accent/.14 si están seleccionados). Es la señal principal de "esto se puede interactuar" en una app de mouse.
  • Clic derecho = menú contextual, en cualquier fila/elemento accionable (listados, árbol, tarjetas). Debe existir también una vía sin botón derecho (botón ⋯) para paridad con touch/teclado.
  • Tooltips con retardo (~350ms) en todo botón de solo-ícono y en controles cuyo propósito no sea obvio por el texto visible; nunca sustituyen a un ContentDialog para respuestas del sistema.
  • Cursores con significado: pointer en clicables, col-resize/row-resize en divisores arrastrables, move en zonas de arrastre (barra de título), text en campos.
  • Anillo de foco solo para teclado (:focus-visible), no al hacer clic con el mouse — evita el "flash" de foco en cada clic que resulta ruidoso en una app mouse-first, sin sacrificar accesibilidad por teclado (Tab/flechas siguen mostrando el anillo).
  • Snap Layouts: al pasar el mouse sobre "Maximizar" se muestra la vista previa de particiones de pantalla — reforzar este detalle si el framework lo expone nativamente (Windows 11 lo da gratis en WinUI/WPF con el chrome nativo bien configurado).
  • Divisores/splitters arrastrables entre paneles (p. ej. lista/árbol ↔ detalle) para que el usuario ajuste el espacio a su gusto; el ancho elegido se persiste por vista.
  • Sin scroll horizontal en tablas cuando sea evitable: preferir ocultar columnas secundarias o usar panel-detalle para el resto de la información antes que forzar scroll-x.

6. Receta para construir una pantalla

  1. CommandBar (Nuevo, Actualizar, acciones contextuales + overflow ···).
  2. Elegir el patrón de datos según el caso:
    • Listado + DetailPopup (default para listados de gestión: proyectos, actividades, usuarios, catálogos…): al hacer clic en una fila u optar "Nuevo", se abre un DetailPopup (overlay de tamaño fijo, listado inactivo detrás, nunca se cierra con clic afuera) con el detalle/formulario y sus acciones (Guardar, Editar, Eliminar). El listado se ve completo e intacto en cuanto se cierra el popup.
    • Listado + Master-Detail: lista con selección simple a la izquierda/arriba, detalle en el sitio a la derecha/abajo, sin modal. Reservado para pantallas cuya función principal es explorar/leer una lista larga (correo) — no para listados de gestión con crear/editar.
  3. Selección múltiple + acciones por lote: casillas en la columna izquierda de la tabla; la barra de estado muestra "N de M seleccionados"; las acciones de lote aparecen en la CommandBar solo cuando hay selección.
  4. Clic derecho en cada fila con el menú contextual estándar: Ver detalle, Editar, Duplicar, Exportar (submenú), separador, Eliminar (danger).
  5. Edición: campos habilitados solo en modo edición; Guardar solo si hubo cambios reales; acciones destructivas siempre confirmadas con ContentDialog (tono warning, Cancelar/Eliminar).
  6. Pie de listado (pie-listado, igual criterio que en la identidad web): líneas por página (5·10·20·50·Todo, default 10, persistente por listado), rango "Mostrando X–Y de N", paginación con ventana deslizante de 5 números, y alto constante entre páginas (filas de relleno invisibles en la última página parcial).

7. Reglas de identidad (do & don't)

  • ✅ Barra de título personalizada (no la nativa del SO) con drag region + minimizar/maximizar/cerrar.
  • ✅ Panel de navegación fijo, con modos expandido/compacto/oculto persistentes.
  • ✅ Tema oscuro/claro y acento del sistema, ambos persistentes; heredar el acento del SO cuando el framework lo permita.
  • ✅ Toda decisión del usuario pasa por ContentDialog; estados no bloqueantes por InfoBar; eventos de fondo por Toast; nada de MessageBox/alert/confirm nativos.
  • ✅ Clic derecho con menú contextual en toda fila/elemento accionable — es la firma de interacción de una app Windows mouse-first.
  • ✅ ComboBox y DatePicker propios (redondeados, estilables); nunca los controles nativos del SO/navegador para estos casos — igual criterio que la identidad web.
  • ✅ Tipografía del sistema (Segoe UI Variable), sin cargar fuentes web — más estable y coherente con el resto de Windows.
  • ✅ Radios de esquina consistentes: 4px controles, 8px superficies elevadas y la ventana misma.
  • ✅ Un solo set de íconos en toda la app (Lucide o Segoe Fluent Icons), heredando color del contexto.
  • ✅ DetailPopup (tamaño fijo, nunca se cierra con clic afuera) para ver/crear/editar el detalle de un ítem de un listado de gestión; Master-Detail solo para pantallas de exploración/lectura pura.
  • ✅ Foco visible solo con teclado (:focus-visible); hover visible siempre (mouse-first).
  • ❌ MessageBox/alert/confirm del sistema. ❌ combos/selects/calendarios nativos sin estilar. ❌ mezclar sets de íconos. ❌ apilar listado + formulario + detalle en una sola pantalla sin separación clara. ❌ usar Toast para pedir una decisión al usuario. ❌ panel de detalle lateral o debajo del listado en pantallas de gestión (usar DetailPopup). ❌ que un DetailPopup cambie de tamaño al moverse entre sus pestañas/secciones internas. ❌ montar ContentDialog/DetailPopup sin portal a document.body (queda atrapado en el stacking context de un ancestro y puede terminar tapado por otro overlay).

Para que una app "se sienta Windows moderna": misma barra de título, mismo panel de navegación, mismos cuatro mecanismos de aviso (ContentDialog/InfoBar/Toast/Flyout) bien diferenciados, clic derecho en todo lo accionable, y los mismos tokens de color/tipografía/radio. Abre UI-UX-WINDOWS.html para verlo funcionando y pide ajustes por el nombre de región/componente.