Sistema de diseño del SGD
Propósito y referencias
El SGD tiene una sola base visual para funcionario y administración. Las paletas visibles Theme LATAM, Theme Adobe Spectrum y Theme Institucional cambian colores semánticos; no cambian estructura, densidad, componentes ni comportamiento. Theme Adobe Spectrum toma Adobe Spectrum como referencia de organización, limpieza visual y acentos azules; es una variante propia del SGD, no una identidad oficial de Adobe. La identidad resultante es propia del SGD: índigo para la variante predeterminada, contenido y superficies neutros, navegación clara y controles precisos para trabajar con documentos.
- El ZIP
Rediseñar pantalla gestión documental.zipaportó la barra de navegación de dos niveles, menú de opciones compacto, tabla de documentos y campos con etiqueta flotante y línea inferior. Su código usa Inter y una escala neutra. No define exhaustivamente todos los estados de diálogos, carga, vacíos y responsive; las reglas de abajo son decisiones del SGD para esos casos. - Guía de estilos de Gob.pe: claridad, lenguaje de trámites y coherencia visual.
- Tokens de Adobe Spectrum y uso del color: decisiones semánticas y superficies organizadas.
- Lineamiento de accesibilidad digital de la PCM: objetivo WCAG 2.2 AA como mínimo para el SGD. La guía de Gob.pe recomienda además contrastes más altos para texto cuando sea posible.
Fuentes de verdad
La especificación progresiva de botones, con inventario de capturas, API, tokens y estados, está en docs/components/buttons.md. La página interna de comparación es /design-system/componentes en el servidor de desarrollo.
La segunda familia, gestión de sesión, define los estados de aviso y expiración, su accesibilidad y la integración pendiente con una política real de inactividad. Su demostración es aislada de la sesión del usuario.
La especificación de diálogos define la superficie compartida, la estructura de cabecera/cuerpo/pie, el cierre “X” en reposo, hover y foco, y las políticas allowed y blocked, además del texto condicional de la confirmación «Regresar a proyecto» (cuadro de las nueve combinaciones). La página de componentes incluye ejemplos de cuerpo corto y largo, descarte de cambios y bloqueo de cierre.
La especificación de alertas flotantes documenta el proveedor Sileo ya instalado, sus cuatro variantes, posición, tokens y comportamiento con un diálogo abierto. Los errores de operación o conexión se notifican fuera del cuerpo; la validación de campos permanece junto a cada campo.
La especificación de tooltips de iconos documenta el componente Radix compartido, su flecha y posicionamiento dinámico, los tokens de contraste fijo y la etiqueta accesible de los botones de solo icono.
La especificación de atajos con Alt documenta la capa de atajos (Button shortcut="G" + ShortcutHintsProvider + diálogo de ayuda ShortcutsHelp): Alt en Windows y Linux, Control en macOS, insignias al mantener el modificador, alcance por diálogo, reglas de asignación por plataforma, preferencia y accesibilidad. Solo se monta en /design-system/componentes; ninguna pantalla real declara atajos todavía.
La especificación de badges de estado documenta anatomía Soft/Solid/Outline, tamaños, iconos opcionales, contraste y correspondencia entre estados y tonos. Los badges informativos se distinguen de los filtros interactivos.
Fuentes alojadas (sin Google)
Inter (variable, latín y latín extendido) y los iconos Material Symbols Rounded se sirven desde app/public/fonts, con @font-face en globals.css y precarga en layout.tsx; no hay peticiones a fonts.googleapis.com ni fonts.gstatic.com. Los iconos son un subconjunto (solo los usados, ≈ 130 KB) con nombre versionado por hash (material-symbols-rounded-subset.<hash>.woff2; icons:build actualiza solo las referencias de globals.css y layout.tsx): un navegador con la fuente anterior no la reutiliza, evitando que un icono nuevo se vea como su nombre en texto (p. ej. «SAVE»). Al usar un icono nuevo: cd app && npm run icons:build (necesita red una vez) y confirmar con npm run icons:check; los iconos que el código elige en tiempo de ejecución se declaran en ICON_EXTRA (scripts/icon-names.mjs). Licencias (Inter OFL 1.1, Material Symbols Apache 2.0) en public/fonts/LICENSES.md.
Anillo de foco: se muestra con teclado y desaparece al soltar el clic. InputModalityInit marca <html data-input-modality> y globals.css lo oculta en botones, enlaces y controles Radix mientras sea pointer (se conserva mientras están pulsados). No crear anillos propios con :focus; usar :focus-visible.
Las reglas de accesibilidad WCAG 2.2 AA (teclado, foco, nombres, contraste, adaptación y movimiento) aplican a todos los componentes de esta guía.
La especificación de tablas, buscador, ordenamiento y columnas documenta la base TanStack Table (useSgdTable, DataTable, AdminDataTable) y DataTableToolbar, TableHeadSortable, TableCellDescription: botón único en barra de herramientas (sin duplicación en <th>), tablas con y sin buscador (acciones alineadas a la derecha sin huecos vacíos), visualización íntegra de dos líneas con Tooltip, ordenamiento funcional por tipos de dato reales (fechas epoch, números, texto, estados) con aria-sort, y persistencia aislada en localStorage por tabla y usuario con useSyncExternalStore.
| Decisión | Fuente en el repositorio | Regla |
|---|---|---|
| Paleta y modo | src/app/globals.css, src/lib/color-theme.ts, next-themes | data-color-theme elige Theme LATAM / Theme Adobe Spectrum / Theme Institucional; .dark elige modo. Las claves persistidas son latam / azul / gobpe. No introducir colores fijos en pantallas. |
| Geometría y superficies | --sgd-* en src/app/globals.css | Compartir espaciado, alturas, radios, sombra y neutros entre las tres paletas. |
| Primitivas | src/components/ui/ | Reutilizar shadcn/ui y Radix; ampliar variantes en vez de copiar componentes. |
| Iconos de sistema | src/components/ui/icon.tsx | Material Symbols Rounded de 16–20 px; mantener logotipos e imágenes tal como vienen. |
| Flujos y datos | rutas src/app/, componentes src/features/ | Mantener permisos, URL de filtros, paginación y conexiones existentes. |
Fundamentos
- Color.
background,card,popover,foreground,muted-foreground,bordereinputforman la base neutra compartida.primary/actionindica acción principal;selectionmarca pestaña o elemento activo;accentes su superficie tenue. Theme LATAM usa índigo#1b0088y rosa rojizo moderado#d11148; Theme Institucional usa rojo#bf0909; Theme Adobe Spectrum usa azul profesional#0b4aa2y selección azul claro#e8f1fc.form-accentpermanece azul en todos los temas.destructive,success,warningeinfoconservan significado en las tres paletas. En modo oscuro se elevan la luminancia de texto e identidad y se oscurecen superficies; no se invierten imágenes institucionales. - Tipografía. Una sola familia, Inter. Se carga como hoja de estilo en
layout.tsx, con Arial como respaldo cuando la red no está disponible; el build no descarga fuentes.--sgd-font-page-title= 24 px parah1;--sgd-font-section= 18 px;--sgd-font-bodyy--sgd-font-menu= 14 px;--sgd-font-table= 13 px;--sgd-font-help= 12 px. Texto funcional nunca menor de 12 px. Usar peso 600 para títulos y encabezados; evitar mayúsculas continuas en texto largo. Los números documentales usantabular-numspara cotejar filas. - Mayúsculas y minúsculas. Tipo oración en todo el producto: minúscula con mayúscula inicial en títulos, etiquetas, encabezados de tabla, insignias, opciones y acciones. Las siglas (SGD, PDF, DOCX, V°B°) y los nombres propios se escriben como son, y los datos se muestran como están guardados. No se usa
uppercasenitext-transform: uppercase; la jerarquía se logra con peso, tamaño y color. Excepciones: los campos donde se escribe un código en mayúsculas (font-mono uppercase) y[&::first-letter]:uppercasepara la primera letra de una fecha.npm run text:checklo comprueba. - Tono de estado (éxito, advertencia, información).
text-success,text-warningytext-info(y sus fondosbg-success/10…) usan los mismos valores en los tres temas y en administración:#14743b,#8a5a00y#175cd3en claro (≥ 4,5:1 sobre su fondo tenue) y sus versiones claras en oscuro (globals.css, junto a--destructive). No usar colores de paleta Tailwind (text-green-600,text-amber-500…) para un estado; tampoco una clasebg-*/text-*sobre unBadge(.sgd-badgemanda y la ignora): el color de un estado lo da la variante (soft-success,soft-warning,soft-error,soft-info,soft-neutral); verfeatures/mesa-partes/constants.ts(REQUEST_STATUS_VARIANTS). - Puntos suspensivos. Los textos de estado y los placeholders usan el carácter único «…» («Cargando…», «Buscar por nombre…»), nunca tres puntos («...»). Excepción: textos dentro de scripts de shell.
- Botón de icono de una fila. Siempre
Button variant="ghost" size="icon"contitle/aria-label(tooltip compartido); no<button>propios contitlenativo (bandeja de Mesa de Partes ya migrada). - Estado de carga de una sección.
SectionLoading(ui/section-loading.tsx) es elloading.tsxde/adminy/dashboard: título, filtros y filas en gris,role="status"con «Cargando…» solo para lectores de pantalla y sin pulso con movimiento reducido. Una pantalla con un diseño muy distinto puede tener su propioloading.tsx. - Escala de iconos. 12 (dentro de una etiqueta), 14 (botones compactos), 16 (en línea), 18 (controles), 20 (navegación), 24 (destacados), 32 (ilustración de una sección vacía o con error) y 40 (aviso de página completa); constantes en
ICON_SIZE(ui/icon.tsx). No usar 13, 15, 22, 28 ni 36. Excepción: la fila de árboles del impacto ambiental (28), por ser una visualización de datos. - Color de estado elegido por el administrador. Se pinta con
customColorProps(hex)(lib/legible-color.ts) sobre unBadge: oscurece (claro) o aclara (oscuro) el texto, sin cambiar el matiz, hasta 4,6:1 sobre su fondo tenue. No pasar el color en crudo a--sgd-badge-color. - Páginas de error y de aviso.
auth/error,not-foundy los avisos de sección usansgd-panel, tokens eIconde 32 px (40 px en página completa); nunca colores de paleta. El código HTTP solo se muestra si corresponde (401 sesión expirada, 403 acceso denegado). - Confirmaciones. Siempre
ConfirmDialog/AlertDialog; nuncawindow.confirm. - Estado final de un documento. Archivado y Anulado se señalan además con una cinta diagonal pequeña en la esquina de la tarjeta (
StatusRibbon); ningún otro estado lleva cinta. Verdocs/components/cinta-estado.md. - Calendario (
Calendar,ui/calendar.tsx). «Hoy» lleva un fondo suave; si además es el día elegido, el círculo de la selección va solo, sin el cuadrado de «hoy» detrás (todaycondata-[selected=true]:bg-transparent). Se comprobó con el día de hoy elegido en claro y oscuro. - Texto de ayuda dentro de un campo (placeholder). Un ejemplo concreto y entendible («Por ejemplo: falta adjuntar el informe técnico firmado.»), nunca la etiqueta repetida («Escribe el motivo…» bajo «Motivo de la observación»). El placeholder no sustituye a la etiqueta ni a la ayuda de obligatoriedad.
- Dato de solo lectura.
ReadOnlyData(nuevo/readonly-data.tsx): ícono solo, en gris suave de 18 px y sin recuadro de color, etiqueta de 12 px y valor de 14 px; el ícono conserva su hueco de 28 px para alinear con el título de la tarjeta y es decorativo. El color de marca queda para lo accionable y para valores destacados. Las iniciales de una persona siguen en su avatar. Catálogo en/design-system/componentes(«Dato de solo lectura»). - Contador de caracteres.
CharCounter(yFieldLabel counter, yshowCountde los campos de subrayado) no se muestra hasta el 80 % del máximo, para que los campos no lleven un «0/2000» permanente; desde ahí, icono y «quedan N», y al límite «límite alcanzado». Catálogo interactivo en/design-system/componentes(«Contador de caracteres»). - Recorrido de estado.
StatusSteps: pasos hecho (verde con marca), actual (de color), pendiente (gris) y alerta (rojo con icono de error) para el paso actual de un estado que pide acción o cerró mal: Observado y Anulado. El estado nunca depende solo del color. Catálogo en/design-system/componentes(«Cabecera de un documento»: en curso, archivado, observado y anulado). - Cabecera de un documento. Tarjeta con ruta, título (
Tipo N° número) conCopyNumberButtony menú ⋮ (Anular), recorrido de estado (StatusSteps) y acciones (Action); «Ver anexos» con contador esViewAttachmentsAction(una sola lectura conuseAttachmentNames; con referencias no se apaga aunque no haya anexos propios). Reglas y estados endocs/components/formularios-documentos.md; catálogo en/design-system/componentes(«Cabecera de un documento»). - Visor y verificador en celular. Cabecera de 56 px (44 px en horizontal), documento a pantalla casi completa, barra inferior de cinco herramientas con icono de 24 px arriba y etiqueta de 12 px completa abajo (Páginas, Buscar, Ajustar, Archivos con insignia de cantidad y Más) y hojas inferiores con tirador para Archivos, Más y Verificación y firmas; sin franjas fijas de anexos, avisos ni texto legal; áreas de 44 px; solo funciones reales del visor. Ver
docs/components/visor-movil.mdy la muestraViewerMobileShowcaseen/design-system/componentes. - Servicios públicos de consulta (Verifica y Seguimiento de documentos). Misma cabecera (80 px, sigla arriba y servicio debajo, cambio de tema con un solo icono), portada a dos columnas de hasta 1440 px con tarjeta de consulta (campos de 52 px, captcha, botón de 48 px), ayuda como enlace que abre una hoja de ejemplo con las zonas marcadas, banda «Cómo consultar» solo en el estado inicial y estados diferenciados (inicio, en proceso, resultado, no encontrado, error). El seguimiento se presenta como línea de tiempo con ramificaciones visibles, relaciones y tabla complementaria; en celular, tarjetas. Especificación en
docs/components/servicios-publicos.md. - Logo institucional.
BrandLogo(src/components/ui/brand-logo.tsx) redondo (círculo completo,rounded-full) y con aro fino; es el único logo de las cabeceras (administración, panel del funcionario, página de inicio y su cabecera). El radio se cambia solo en ese componente; no se escribe<Image src="/minjus.jpg">a mano. - Cantidades y plurales. Todo contador variable concuerda en número: «1 documento», «2 documentos», «1 requiere firma», «3 requieren firma». Se escribe con
countLabel(src/lib/plural.ts), que además separa los miles con el formato de Perú; no se escribe{n} documentosa mano. - Iconografía. Toda la interfaz usa
Icon(Material Symbols Rounded, vectorial) con peso 400. Tamaños: 16 px junto a texto y estados, 18 px dentro de controles, 20 px en navegación, 24 px para acciones destacadas. Usar nombres de ligadura de Material Symbols; dar nombre accesible al botón que contenga solo icono. No cambiar logos. Iconos por acción (criterio común): toda acción que abre el PDF de un documento (el visor o una pestaña nueva con el PDF: «Ver documento», «Ver PDF», «Visualizar PDF», «Ver Doc.») llevapicture_as_pdf, en menús, botones y filas de tabla; el ojo (visibility) queda para «Ver detalle». En las listas de anexos, el botón «Ver» lleva el icono del tipo de archivo (fileTypeOf,src/lib/file-type.ts): PDFpicture_as_pdf, documento de textodescription, hoja de cálculotable_chart, imagenimage, presentaciónslideshow, comprimidofolder_zipy cualquier otrodraft; sin color y sin logos de marca. Catálogo en/design-system/componentes(«Iconos por tipo de archivo»). - Espaciado. Escala
--sgd-space-1/2/3/4/5/6/8= 4/8/12/16/20/24/32 px. Formularios: 8–12 px entre filas. Espacio exterior: una sola medida de 16 px (p-4/gap-4) en administración y en el usuario final — entre el panel lateral y el contenido, entre tarjetas, entre la barra de pestañas (tarjeta) y el contenido, y con los bordes de la ventana; el asa de redimensión del panel lateral ocupa justo ese espacio de 16 px y queda centrada entre ambas tarjetas. Columnas de formulario: 16 px. La densidad debe permitir muchas filas sin controles diminutos. - Tamaños. Cabecera 64 px, subnavegación 48 px, controles 40 px, controles compactos 36 px, campos de línea inferior 52 px, encabezado de tabla 44 px y filas de al menos 48 px. Celdas: 12 px horizontales y 10 px verticales. Objetivos táctiles de 40 px siempre que la composición lo permita.
- Bordes y elevación. Radios de 6 px en controles y 8 px en paneles. Borde de 1 px y sombra
--sgd-shadow-panel; los menús usan--sgd-shadow-popover. Evitar degradados decorativos.
Componentes y estados
| Componente | Regla |
|---|---|
| Cabecera y menús | Cabecera neutra, identidad a la izquierda y utilidades a la derecha. Un solo grupo activo según usePathname: el de la página o submenú seleccionado. Solo ese grupo usa superficie accent, texto primary y línea selection; abrir otro menú no traslada la línea. Desplegado, hover y foco son estados independientes. Submenús Radix con fondo popover, fila de al menos 40 px y foco visible. |
| Apariencia | Tres tarjetas Theme LATAM, Theme Adobe Spectrum y Theme Institucional con descripción, muestras y miniatura esquemática; borde y marca de selección. La opción de modo es independiente. Se persiste en localStorage; COLOR_THEME_LABELS centraliza los nombres visibles. Los identificadores internos son latam, azul y gobpe; valores anteriores adobe migran a azul. Sin preferencia se inicia en Theme LATAM. |
| Lateral | Misma jerarquía de grupo/elemento, con activo accent + primary. En escritorio, la bandeja queda pegada a la barra de pestañas, ocupa el alto visible bajo cabecera/subnavegación y permanece fija durante el scroll del contenido; si sus categorías exceden el alto, se desplazan dentro de la bandeja y los controles inferiores siguen visibles. El espacio inferior pertenece solo al contenido, no al lateral. Las tarjetas de ambas pestañas del Dashboard conservan el mismo respiro lateral: 12 px en móvil, 16 px desde sm y 20 px desde lg. Mantener etiqueta legible e indicador de bandeja. En pantallas pequeñas usar el panel móvil existente con separación vertical. |
| Pestañas y breadcrumbs | Activo reconocible por texto, borde o línea además del color; ruta actual indicada por aria-current. Separadores discretos. |
| Botones | Primario para una acción dominante por zona; outline para acción secundaria; ghost para utilidades; link para acciones ligeras. Deshabilitado visible y semánticamente deshabilitado. Mostrar carga con texto y/o icono de progreso, sin cambiar anchura bruscamente. |
| Badges de estado | Badge/StatusBadge: Soft en tablas; Solid solo para énfasis puntual; Outline con contraste sobre la superficie real. Verde éxito, rojo fallo, naranja atención, azul información y gris neutral, en las tres paletas. Tres tamaños e iconos opcionales; texto obligatorio y cursor informativo. Ver components/badges.md. |
| Búsqueda, filtros y favoritos de tablas | Identidad visual LATAM con patrones de búsqueda, filtrado y favoritos: barra compacta (buscador en vivo + «Más filtros · N»), desplegable Filtros/Favoritos con checks múltiples, panel lateral para fechas exactas y texto, chips de criterios. Ver components/tables.md §7b. |
| Borrar contenido en campos | Los campos de texto con FloatingUnderlineInput muestran una «×» (hover/foco: círculo gris) cuando tienen información; borra todo y devuelve el foco. No aplica a fechas, contraseñas, números ni campos deshabilitados/solo lectura. |
| Campos y selectores | FloatingUnderlineInput y FloatingUnderlineSelect para formularios de documentos. Etiqueta siempre accesible, línea inferior azul en foco, error rojo con icono y mensaje. Opciones Radix navegables por teclado. Con valor seleccionado muestra una «X» (color primario, antes del chevron) para quitarla; Supr/Retroceso también (clearable={false} en obligatorios; en Select directo, onClear + hasValue). No usar solo color para validar. |
| Lista de opciones común a todos los selectores | .sgd-listbox (fondo, borde, sombra) y .sgd-option (40 px, marca a la izquierda, resaltado --accent; las filas contiguas (.sgd-option y también .sgd-menu-item, las subopciones del menú superior y del menú móvil) se separan 4 px (--sgd-space-1) para que el fondo de la opción elegida y el resaltado de la siguiente no se peguen) en globals.css, aplicadas en Select, DropdownMenu, Command, SearchableCombobox y MultiSelectCombobox; ListboxStatus para Buscando/Sin resultados/error; chevron único expand_more; OptionCombobox para listas estáticas con búsqueda. Muestra en /design-system/componentes. Ver components/selectores-busqueda.md §Uniformización. |
| Selectores con búsqueda en el propio campo | SearchableCombobox (ui/searchable-combobox.tsx): se abre con clic y se escribe en el mismo campo (sin buscador dentro del desplegable); filtra mientras se escribe sin distinguir mayúsculas ni tildes; escribir es una búsqueda temporal y la selección confirmada solo cambia al elegir (clic o Enter); al cerrar sin elegir vuelve el nombre anterior; ↑/↓/Enter/Escape sin perder la edición normal del texto; subrayado con etiqueta flotante siempre arriba. Lo usan EntityCombobox y sus *Combobox, CitizenCombobox, LocationCombobox y FloatingSelectField. Ver components/selectores-busqueda.md. |
| Botón de texto subrayado (enlace) | Button variant="brandLink" / inverseLink: el subrayado afecta solo al texto (<span class="sgd-link-text"> que agrega Button), nunca al icono ni al hueco icono–texto ni como borde del botón; hover con fondo --accent sobre todo el botón sin desplazamientos; mano y clic en toda el área; foco de 2 px; deshabilitado al 50 %. Ver components/buttons.md («Variante enlace»). |
| Texto sin contenedor (terciario) | Button variant="brandTertiary" / dangerTertiary |
| Fondo de los campos | --sgd-field-background (globals.css): superficie de la tarjeta en claro y fondo hundido en oscuro. Lo usan Input, Textarea, Select, OptionCombobox, el botón outline y la casilla, para que un campo vacío dentro de una tarjeta o un diálogo blancos no se vea gris como uno deshabilitado; los deshabilitados usan --sgd-surface-muted. No usar bg-background en campos. |
| Campo de fecha | DateField (ui/date-field.tsx; DatePicker de ui/ y de admin/ son envoltorios con la misma API): se escribe dd/mm/aaaa con las barras automáticas («25121990» → «25/12/1990»; día 4-9 y mes 2-9 se completan con cero; se puede pegar aaaa-mm-dd) o se elige en el calendario (ícono o Alt + ↓). Valida mes 01-12, día 01-31, meses con menos días, bisiestos, año 1900-2100 y minDate/maxDate; el motivo sale bajo el campo (role="alert") y con texto incompleto o inválido el valor es vacío. Utilidades en lib/date-input.ts. |
| Calendario | Fondo blanco (bg-popover); desplegables de mes y año con el Select del sistema (no el <select> nativo); hover del día bajo el mouse más fuerte que la franja de la semana; la barra de navegación no intercepta clics (pointer-events-none, solo sus flechas). |
| Pestañas con línea | <TabsList variant="line"> (ui/tabs.tsx, estilos .sgd-tabs-line): solo la activa lleva el subrayado de 3 px; hover = fondo suave, sin subrayado; foco con contorno visible. Una pestaña puede llevar un punto de estado de 6 px (bg-success, aria-hidden) junto con un texto solo para lectores («agente conectado en este equipo»): el estado nunca se comunica solo con el color. La variante predeterminada (pill) no cambia. |
| Comando copiable | CommandBlock (ui/command-block.tsx): recuadro monoespaciado que se ajusta a varias líneas (no ensancha el contenedor) con el ícono de copiar a la derecha; copia el comando original completo, confirma con notifySuccess y no cierra el diálogo. copyText (mismo archivo) se exporta para otros botones de copiar. Sin comando publicado (command={null}) lo avisa y el ícono queda deshabilitado. |
| Ruta con copiar y abrir | PathRow (ui/path-row.tsx): ícono de carpeta, etiqueta, ruta en monoespaciado (break-all, nunca ensancha el contenedor) y dos acciones brandOutline de 36 px: copiar (cuadrado, con tooltip; cambia a «check» 2 s, avisa con notifySuccess y, si el navegador lo niega, pide copiarla con el teclado) y «Abrir» (con loading). Quien la usa decide onOpen: el navegador no abre carpetas del equipo, lo hace el agente local (open_folder). La usa el popup del agente para la carpeta de documentos. |
| Logos de sistema operativo | WindowsLogo, AppleLogo, LinuxLogo (ui/os-logos.tsx): SVG propios, decorativos (aria-hidden) y del color del texto, para selectores como el del popup del agente (components/agente-local.md). |
| Control segmentado | SegmentedControl (ui/segmented-control.tsx, estilos .sgd-segmented): 2 a 4 opciones excluyentes que cambian un modo o una vista y se aplican al instante (p. ej. «Sin impuestos |
| Menú de usuario (avatar) | UserMenuHeader + UserAvatar (components/user/), usados por AdminHeader y UserHeader. Cabecera a sangre completa con fondo --accent tenue: avatar de 60 px (foto de Zitadel si existe; si no, iniciales sobre --primary), nombre, correo, roles reales de /me con nombre legible (lib/role-label.ts: ADMIN → «Administrador», MESA_DE_PARTES → «Mesa de partes»; hasta 2 etiquetas y «+N»; nada si no hay roles) y, en el funcionario, la oficina activa con su sede. Anillo --primary en el avatar mientras el menú está abierto (USER_MENU_TRIGGER_RING). Opciones de 40 px con ícono de 18 px: administrador = Preferencias · Panel del funcionario · Cambiar de cuenta · Cerrar sesión; funcionario = Preferencias · Cambiar de cuenta · Cerrar sesión. «Cerrar sesión» va en rojo (.sgd-option-danger) también al resaltarla. «Cambiar de cuenta» y «Cerrar sesión» son <a> (Route Handlers: con <Link> Next los precargaría). |
| Mis preferencias | PreferencesDialog (components/user/preferences-dialog.tsx), que abre «Preferencias» en ambos menús. Pestañas con línea: Mis datos (nombre, correo, documento, cargo y oficina de solo lectura; celular o anexo editable por la propia persona con PATCH /me, validado igual en cliente y servidor; Guardar/Descartar y confirmación de descarte), Apariencia (AppearancePanel, se aplica al instante), Notificaciones (informativa: los tres avisos que existen y «Próximamente»; hoy cada oficina decide avisos y canal) y Seguridad (último acceso en hora de Lima y enlaces a la consola de Zitadel para contraseña, verificación en dos pasos y foto: no se duplica en el SGD; la fila de verificación en dos pasos muestra si está «Activada» o «No activada» según GET /me → mfa, con «Administrar» o «Activar», y si no se pudo consultar no afirma nada y ofrece «Configurar»). El nombre, correo, documento, cargo y oficina los cambia un administrador desde Usuarios. |
| Menús y submenús de navegación | Menú superior del funcionario (.sgd-nav-trigger), subopciones (.sgd-menu-item), pestañas, menú lateral de administración (.sgd-nav-row) y árbol (.sgd-tree-row): al pasar el mouse o enfocar con teclado el texto y el ícono cambian juntos (los íconos grises de reposo heredan el color del texto; los de color propio no). En las subopciones del menú superior el texto pasa a --accent-foreground y la viñeta de la fila (.sgd-menu-dot, gris en reposo) toma el color primario; la subopción actual conserva texto y viñeta primarios. Una opción de peligro lleva .sgd-option-danger (también «Eliminar» de los favoritos y la acción de peligro de Recepción de interoperabilidad). |
| Íconos de opciones | En cualquier fila .sgd-option (menús, listas, selectores) los íconos grises de reposo (text-muted-foreground, text-foreground/…) toman el color del texto al resaltar la fila con mouse o teclado; los íconos con color propio (primario, de estado) no cambian. Una opción de peligro lleva .sgd-option-danger: texto e ícono rojos también resaltada. |
| Interruptor | Switch (ui/switch.tsx, Radix): activa o desactiva una opción al instante o al guardar. Siempre con etiqueta visible asociada (<label htmlFor>; el clic en la etiqueta también lo activa). Dos medidas: normal (44 × 24 px, formularios y filas) y size="sm" (28 × 16 px, encabezados o filas compactas con texto de 11 a 12 px); la pequeña amplía su área de clic a 24 px de alto con un margen invisible (WCAG 2.2 AA, objetivo mínimo de 24 px) sin cambiar su aspecto. Encendido = --primary; apagado = --input; foco con anillo visible; deshabilitado al 50 %. Espacio o Enter lo cambian. Para elegir entre vistas usar SegmentedControl; para varias opciones de una lista, Checkbox. Galería: /design-system/componentes («Interruptor»). |
| Mapas de calor | CalendarHeatmap (actividad por día, una columna por semana) y MatrixHeatmap (categoría × categoría) en ui/heatmap.tsx, estilos .sgd-heat*. Escala derivada del color primario del tema (tone="destructive" para retrasos y pendientes, tone="success" para ahorro e impacto ambiental); cuadrícula ARIA navegable con flechas; globo inmediato; número en negro o blanco según el contraste real. Alcance por rol: el trabajador ve lo suyo, la jefatura lo suyo, toda su oficina y cada persona de su oficina, la alta dirección todas las oficinas o una oficina concreta, con bajada de nivel por clic; lo decide el permiso en el servidor. Ver mapas de calor. |
| Árbol con líneas guía | .sgd-tree / .sgd-tree-node / .sgd-tree-row (globals.css), usado por el menú de administración expandido: guía fina de 1 px por rama; con el mouse o el foco de teclado la rama se resalta (2 px) y forma una «L» hacia la opción y sus niveles padres; la opción seleccionada (data-active="true") conserva su «L» con el trazo normal. Solo hover/foco: no cambia la selección. Solo una opción activa: se elige la ruta más específica. |
| Menú lateral redimensionable | SidebarResizeHandle (ui/sidebar-resize-handle.tsx, estilos .sgd-resize-handle y .sgd-sidebar-aside en globals.css). Tirador de tres puntos: pastilla de 8 × 26 px (borde, fondo de tarjeta y tres puntos verticales en --muted-foreground) centrada sobre el borde del panel, siempre visible; pasa al color primario cuando el asa se «arma», al enfocar con teclado y al arrastrar. Misma pieza en el visor de PDF de file-service (panel de firmas y panel de miniaturas). Usado por el menú de administración y por la barra de Bandejas del funcionario (sidebar-icgd.tsx, ancho por defecto de 300 px, donde termina la pestaña «Documentos» del menú superior, guardado en sgd_bandejas_sidebar_width): se arrastra el borde derecho entre 220 y 420 px (288 px por defecto; el riel colapsado de 68 px es fijo). El ancho vive en --sgd-sidebar-width y durante el arrastre se escribe directamente en el panel, una vez por fotograma, sin transición ni renderizados de React; al soltar se guarda en el navegador (sgd_sidebar_width). Teclado en el asa (role="separator"): ← → (16 px, Mayús 64 px), Inicio/Fin (mínimo/máximo), Enter y doble clic restablecen. El menú es blanco (bg-card) y su lista se desplaza sin barra visible (.sgd-scroll-hidden). Al desplegar un grupo la lista sube sola con una animación de ≈250 ms (instantánea con «reducir movimiento») hasta que se ven sus opciones, sin subir el título por encima del borde; al cargar o navegar, la opción activa se desplaza a la vista; el submenú flotante del menú colapsado se abre hacia arriba cuando no cabe hacia abajo (alineado con el borde inferior del ícono) y, si ni así cabe, se limita a la ventana con scroll interno. Ejemplo operable en /design-system/componentes («Menú lateral redimensionable», sidebar-showcase.tsx). Zona de agarre de 14 px que empieza a 2 px del borde del panel, por fuera, para no pisar la barra de desplazamiento de su lista. |
| Menú de administración por secciones | ADMIN_NAV_SECTIONS (lib/admin/nav-data.ts): secciones por uso (Operación diaria, Configuración, Contenido y reportes, Control) que agrupan grupos por relación, con dos niveles como máximo (grupo y opción). Cada sección es un role="group" con encabezado (oculto a la vista cuando el menú está contraído, donde una línea separa las secciones). ADMIN_NAV es la lista plana que usan el buscador, la ruta activa y las migas de pan. Cada grupo lleva una description (texto emergente al pasar el mouse; en el menú contraído, encabezado del flyout) y la etiqueta «Paso X de la guía» (guideStepsLabel). «Guía de inicio» (ADMIN_GUIDE_LINK, ícono checklist) va fija bajo el Dashboard y abre /admin/guia, que lista los pasos de lib/admin/guide-steps.ts con su enlace y, donde se puede comprobar con datos reales, el estado «Con datos» / «Sin datos» / «Sin comprobar» (texto e ícono, nunca solo color). |
| Seguimiento del documento (cadenas largas) | follow-up-modal.tsx: dos paneles con desplazamiento propio, proporción 60 % / 40 % (SidebarResizeHandle, se guarda como proporción), maximizar y restaurar como la ventana de firma, líneas guía .sgd-tree (el mismo quiebre en «L» del menú de administración) y detalle con 1, 2 o 3 columnas por consulta de contenedor. En cadenas profundas (más de 20 niveles) el desplazamiento horizontal acompaña al vertical: 0 arriba y el necesario abajo para leer el último documento, con filas de ancho mínimo min(ancho del panel, 38rem), tope por la fila más profunda a la vista y degradado en el borde izquierdo. Patrón reutilizable para árboles con sangría profunda. En celular, pestañas «Cadena |
| Avisos con «×» (Callout) | Callout (components/admin/callout.tsx): los de tipo info y success llevan una «×» (aria-label="Cerrar aviso", botón ghost de 36 px) y el cierre se guarda en el navegador por pantalla y título (sgd_callouts_dismissed), para que no reaparezcan en cada visita; las advertencias (warning) no se pueden cerrar. dismissible fuerza uno u otro (se usa false dentro de diálogos) e id fija la clave si cambia el título; resetDismissedCallouts() los vuelve a mostrar. |
| Marca de la cabecera de administración | AdminBrand (components/admin/brand.tsx): **LOGO |
| Tabla con título en la barra | AdminDataTable toolbarTitle / toolbarDescription (y SgdDataTable toolbarStart): título y conteo comparten fila con el selector de columnas; «Filas por página» va en el pie junto a la paginación (PaginationBar showPageSize). |
| Recorrido guiado | GuidedTour (ui/guided-tour.tsx): botón de ícono («Recorrido guiado») que recorre las zonas de una pantalla; cada paso resalta su zona (resto oscurecido y difuminado) con una tarjeta de título y texto. Pasos con target (selector) o sin él (ventana centrada); los pasos sin zona visible se saltan solos. Teclado: flechas, Escape y foco que vuelve al botón; ventana final con confeti (omitido con «reducir movimiento»). El del SGD es DashboardTour (user/dashboard-tour.tsx, 10 pasos), con data-tour / data-nav-group en la cabecera y el menú. |
| Ilustración de bandeja (barra de bandejas, contraída y expandida; 32 × 32 px) | TrayIcon (ui/tray-icon.tsx): una ilustración propia por bandeja en el estilo del estado vacío; borde currentColor, acentos de marca, decorativa (aria-hidden). La cifra va como insignia sobre el ícono. Ver docs/BANDEJAS.md. |
| Diálogo redimensionable (opt-in) | dialog-resizable.tsx: arrastre de bordes y esquina inferior derecha (flechas del teclado incluidas), botón Maximizar/Restaurar y mínimo/máximo dentro de la pantalla; sin tocar DialogContent. Hoy solo la ventana de firma. Ver components/dialogs.md. |
| Ventana de firma digital | SignDocumentDialog: visor PDF con zoom (50–300 %) y navegación de páginas a la izquierda y panel a la derecha desde lg (una columna debajo, visor primero y pie siempre visible); el panel separa «Firma digital» (motivo) de «Representación visible en el PDF» (sello, cargo, ubicación en puntos PDF que se conserva a cualquier zoom). Estados preparando / firmando / recibiendo / éxito / cancelada / error; sin cierre mientras Firma Perú está abierta (no hay «cancelar» en el agente) y «firmado» solo tras recibir el PDF. «Leer texto del PDF» reutiliza pdf.js por página (sin OCR); «Ubicar sello» permite página/coordenadas por teclado con límites y bloqueo existentes. Muestra local sin firma/carga en #pdf-heading. Ver components/firma-digital.md para límites y pruebas pendientes. |
| Filtros | Primera fila con criterios frecuentes; secundarios bajo “Más filtros”. “Limpiar filtros” restaura la URL base. Mantener el estado en la URL para paginación y recarga. |
| Tablas y paginación | Encabezado sobre superficie muted, cuerpo neutro y hover sutil. Texto de 13 px y números tabulares; scroll horizontal dentro del panel cuando las columnas no caben. DataTableToolbar para barras con o sin buscador (acciones alineadas a la derecha sin huecos vacíos) y selector único de columnas (tune 18 px, sin duplicar en th). Densidad adaptable: TableRow con min-h y TableCellDescription con 2 líneas completas sin corte e interlineado cómodo, más Tooltip con texto completo. Ordenamiento funcional con TableHeadSortable y useSgdTable por tipos reales (fechas epoch, números, texto es-PE, estados) con aria-sort. Columnas indispensables fijas (required: true), salvaguarda contra ocultar todas las columnas, botón «Restablecer» y persistencia aislada en localStorage con useSyncExternalStore. Ver components/tables.md. Acciones por fila con botón ≥36 px y menú Radix. Paginación con área de selección legible. Estado vacío con título, explicación y acción cuando procede. |
| Gráficas del dashboard | Cabecera uniforme en ambas pestañas: fila superior con icono del tipo activo (barras/líneas/circular, cambia con el selector) y título alineados en el mismo eje horizontal centrado con las acciones a la derecha (tipo, descargar PNG, pantalla completa; botones compactos size-8 min-h-8 min-w-8), ubicando la descripción breve en la línea inferior completa. La vista expandida conserva selector y descarga, con el botón de reducir como cierre explícito. Leyenda interactiva: solo el clic en un indicador de la leyenda lo oculta o lo muestra (clic en la gráfica no filtra); el oculto queda atenuado y con el nombre tachado (line-through), como la referencia; la gráfica y el total se recalculan con los visibles (mínimo 1), con aria-pressed y foco por teclado. El hover de barras, puntos, slices y leyenda usa el Tooltip compartido (negro con flecha), no title nativo. Rige también para la dona y barras del dashboard del admin. Implementado en chart-card.tsx/chart-views.tsx (ChartCard, ChartTypeSwitcher, ChartExpandButton, ChartDownloadButton, ChartDialog, useHiddenKeys). Gráficas hechas a mano con d3 (escalas y formas); recharts fue retirado de app/ por estar sin uso (ui-admin conserva el suyo). Regla de exportación: en SVG usar fill/stroke directos con var(--chart-*); currentColor no sobrevive al PNG. |
| Tarjetas, diálogos y notificaciones | Paneles con borde y sombra discretos. Diálogos con superficie card, fondo atenuado, cabecera fija, cuerpo desplazable y pie de acciones visible con padding de 32 px en escritorio. Dialog closePolicy="allowed" permite X, Escape y clic exterior; un formulario editado pide confirmar el descarte. blocked los impide y se reserva para los dos estados de sesión. En AlertDialog, el cierre nunca acepta una confirmación. Cierre compartido de 44 px con un único anillo de foco; no duplicar el botón. Alertas flotantes con Sileo, texto e icono de estado, cierre accesible, colores semánticos y barra de progreso inferior fina (2 px) y decreciente con pausa en hover/foco; el color solo refuerza. |
Composición de gráficos y leyendas
- Igualar alturas en grupos comparables cuando la composición lo amerite, adaptando también su contenido interior: en los cards de gráficas del Dashboard (tanto en Resumen de gestión como en Impacto ambiental), los cards de una misma fila mantienen una altura común y equilibrada para que sus bordes superiores e inferiores queden alineados entre extremos y centrales. Se evita que los cards terminen a diferentes alturas o que se alarguen con vacíos excesivos. Para ello, el contenido interior se adapta proporcionalmente: las barras ocupan ~256 px, las gráficas con leyenda inferior (como la comparativa diaria) ajustan su plot a ~216 px para que plot + leyenda sumen ~252 px, y las donas con leyenda lateral se centran verticalmente dentro del contenedor compartido. En móvil, al apilarse en una sola columna, la altura se adapta de forma natural a su contenido.
- Leyendas breves (una o dos series, o pocas etiquetas cortas) debajo del gráfico, con distancia uniforme. Leyendas extensas o con etiquetas largas al costado cuando el ancho del card lo permita; el patrón
.sgd-chart-legend-container/.sgd-chart-legend-layoutensrc/app/globals.cssactiva la distribución lateral desde 19 rem (ajustada para cuadrículas de 3 columnas en escritorio) y la apila debajo en contenedores más estrechos y móvil. Los textos pueden envolver y no se recortan. - Mantener la semántica e interacción del componente existente: etiquetas visibles, color más texto, botones
aria-pressedcuando la leyenda filtra, al menos una serie visible y Tooltip compartido. Usar los tokens--sgd-space-*,--chart-*,cardymuted-foregrounden las seis apariencias. Implementación:src/components/user/chart-views.tsx,pie-chart-categories.tsx,documents-comparison-chart.tsx,bar-chart-thin.tsx,documents-charts-section.tsxyenvironmental-impact.tsx; d3 sigue siendo la librería de formas y escalas. - En ejes con fechas, reducir las marcas visibles según el ancho real del gráfico para que sus etiquetas no se solapen en móvil; mantener la serie completa y la leyenda.
documents-comparison-chart.tsxusa.sgd-chart-axis-containerpara espaciar las fechas en cards estrechos.
Para todo elemento interactivo: hover cambia superficie o borde sin desplazar geometría; focus-visible muestra contorno de 2 px; seleccionado usa aria-current, aria-selected o equivalente; deshabilitado conserva texto reconocible; carga bloquea acciones duplicadas; errores se describen junto al campo. Las cuatro categorías de estado incluyen texto o icono.
El cursor se define por semántica en src/app/globals.css: botones habilitados, enlaces con destino, pestañas, opciones de menú, iconos dentro de acciones, checkbox/radio y selectores muestran pointer. Los controles con disabled, aria-disabled="true" o data-disabled no muestran la manito. Campos de texto y áreas editables conservan el cursor de texto; encabezados, tarjetas y superficies informativas no reciben cursor de acción. La superficie del toast permanece informativa y su control «Cerrar» sí es accionable. No repetir cursor-pointer en cada pantalla para corregir controles nativos.
En la navegación del funcionario (src/components/user/user-subnav.tsx y user-nav-dropdown.tsx), la ruta actual decide el único menú y submenú activos, también tras recargar o usar Atrás/Adelante. La apertura del Popover se expresa con aria-expanded/data-expanded, sin modificar data-active ni el borde inferior. Escape o clic exterior solo cierran el desplegable. El panel móvil conserva esta misma selección y recalcula qué grupo expandir al cambiar de ruta; los submenús colapsados se retiran del foco y del árbol accesible con inert/aria-hidden. La selección simulada de /dev-preview-gap es exclusiva de esa vista de desarrollo.
Árboles con sangría profunda: desplazamiento, contraer y expandir
Patrón para listas en árbol que pueden tener decenas de niveles (hoy, el árbol del modal «Seguimiento»; especificación completa en docs/components/arboles-sangria-profunda.md).
- Problema: cada nivel suma unos 23 px de sangría; con 30 niveles o más, el texto de las filas de abajo queda fuera de la vista.
- Regla: el desplazamiento horizontal acompaña al vertical. Arriba del todo es 0 (sangría normal); al bajar, la lista se corre sola a la derecha en proporción al avance; abajo del todo llega al máximo y el último elemento se lee con el mayor ancho posible. Al subir, vuelve a la izquierda. Es un único movimiento continuo, sin saltos.
- Ancho mínimo de fila:
min(ancho del panel, 38rem). Mientras las filas quepan, el árbol se ve y se comporta como siempre: sin barra horizontal ni corrimiento. - Tope: nunca se corre más que la sangría de la fila más profunda que está a la vista (evita paneles en blanco en árboles con una sola rama profunda).
- Señales: degradado de 24 px en el borde izquierdo mientras haya filas recortadas. La barra horizontal nativa se oculta y su lugar lo toma
DeepTreeScrollbaren el pie del panel: pista fina y larga (hasta 20 rem) con el tramo visible y el rótulo «Desplazamiento horizontal»; se arrastra, se pulsa y responde a las flechas, Inicio y Fin (role="scrollbar"). El gesto horizontal del trackpad y Mayús + rueda siguen funcionando. - Interacción: el ajuste solo se aplica cuando cambia el desplazamiento vertical, al abrir o cerrar ramas, al filtrar o al cambiar el ancho del panel; quien arrastra la barra horizontal no es contrariado.
- Contraer y expandir: cada rama con hijos lleva una flecha (
expand_moreabierta,chevron_rightcerrada) conaria-expandedy nombre «Contraer / Expandir + documento». Estado inicial: abierta solo la ruta hasta «Usted está aquí». «Expandir todo» abre todas las ramas; «Contraer todo» las cierra todas (queda el nivel superior) y el botón alterna su texto según el estado. Una rama contraída muestra «N documentos más (rama contraída)», que también la abre. Con búsqueda o filtro activos todo se muestra abierto y las flechas no aparecen. - Detalle al elegir: al pulsar un documento queda resaltado (
aria-current) y su detalle aparece en el panel derecho (título con estado, «Ver documento», expediente, oficina, elaborado por, fecha y estado del trámite); en pantallas angostas el detalle va debajo. - Implementación: hook
useDeepTreeScrolly claseDEEP_TREE_ROW_CLASSensrc/components/ui/deep-tree-scroll.ts(variable CSS--tree-list-w); uso real enfollow-up-modal.tsx. Ejemplo interactivo en/design-system/componentes(sección «Árbol con sangría profunda»,deep-tree-showcase.tsx, solo desarrollo).
Cabecera de las aplicaciones y cambio de tema (estándar común)
Válido para la portada del SGD, la Mesa de Partes Virtual y el Verifica (y como referencia para el visor):
- Nombre en dos líneas: arriba la sigla de la institución (12 px, semibold, gris) y debajo el nombre del servicio (14 px en pantallas menores y 16 px desde
lg, negrita, color primario). Nunca por debajo de 12 px. - Cambio de tema con un solo icono: luna en modo claro (pasa a oscuro) y sol en modo oscuro (pasa a claro), no un selector de dos iconos. Círculo de 36 px, icono de 20 px,
aria-labelytitle«Cambiar a modo oscuro» / «Cambiar a modo claro», foco visible. - Alto de 80 px y logo circular de 44 px en las portadas.
Sustento normativo de patrones y formularios
Los patrones que recogen datos de la ciudadanía o producen constancias tienen respaldo en normas. La referencia central (fuentes verificadas, vigencia, matriz y pendientes) es docs/normativa/NORMATIVA-FORMULARIOS-Y-SERVICIOS-DIGITALES.md; la regla general está en AGENTS.md (raíz), «Sustento normativo de requerimientos y formularios». Aquí solo se documenta qué exige la norma a cada patrón; las reglas de cada trámite viven en su documentación funcional.
Distinguir siempre el tipo de regla: N obligación normativa (con artículo), I criterio institucional, F decisión funcional del proyecto y UX recomendación de diseño. Ninguna norma establece colores, distribución ni estilo: esas decisiones son de este documento y se justifican por usabilidad y accesibilidad, no por una cita legal.
| Patrón | Referencia normativa (estado Oficial el 30/10/2026) | Regla de interfaz | En el Design System |
|---|---|---|---|
| Campo obligatorio y opcional | TUO 27444, art. 124; DS 007-2024-JUS, arts. 13 y 15 (acceso a la información) | N El conjunto de datos obligatorios lo fija la norma y el TUPA de cada trámite; en acceso a la información los datos de contacto y demográficos son opcionales. UX El campo opcional lleva la palabra «opcional» en la etiqueta, no el asterisco. | FloatingUnderlineInput y FieldLabel; sin variante «opcional» documentada: pendiente. |
| Validación de admisión | TUO 27444, arts. 135.1 y 136 | N Un defecto subsanable no impide presentar: se observa después, con dos días hábiles para subsanar. UX Validar y orientar, sin bloquear lo que la norma no exige. | Estado de error del campo; la regla de no bloqueo se decide por trámite. |
| Constancia o cargo de recepción | TUO 27444, art. 135.2; DS 007-2024-JUS, art. 17.2; DS 029-2021-PCM, art. 46 | N Fecha, hora, lugar o canal y, según el caso, folios y documentos acompañados. | Pantalla de confirmación con esos datos; sin componente propio: pendiente. |
| Casilla de aceptación o consentimiento | TUO 27444, art. 20.4; Ley 29733, art. 5 y 14.1; DS 016-2024-JUS, arts. 3, 5 y 10 | N Cuando se pide, es expreso, informado, no condicionante y revocable. UX Checkbox sin premarcar, con el texto completo al lado. | ConsentOption (gov-desk, features/privacidad); ver components/casilla-estados-y-privacidad.md. |
| Aviso de privacidad | Ley 29733, art. 18; DS 016-2024-JUS, arts. 6 y 7 | N Informar antes de recoger: finalidad, destinatarios, banco de datos, carácter obligatorio o facultativo, plazo, derechos. UX Resumen corto y enlace a la política completa. | PrivacyNotice y página de política (gov-desk), con contenido configurable y estado de aprobación; ver components/casilla-estados-y-privacidad.md. |
| Términos y condiciones | Ley 31736, art. 4.1 | N Conformidad con los términos al registrarse. | Página de lectura y resumen en el registro (portal de gov-desk). |
| Aviso de contingencia | Ley 31736, arts. 7.2 e y 8.2 | N Comunicar la falla con fecha, hora y duración. | Alerta de role="alert"; sin patrón propio: pendiente. |
| Consulta pública de trámite (Seguimiento) | TUO 27444, art. 171.1 (fuente secundaria); TUO de la Ley 27806 (excepciones); Ley 29733 y DS 016-2024-JUS; WCAG 2.2 | N Reservar lo reservado y tratar solo los datos necesarios. F/UX Estados de la consulta separados de los del trámite; mensajes con causa y recuperación. | components/seguimiento-estados.md: 26 estados, reglas de duplicados, límite y tiempo agotado. |
| Glosa, CVD y QR | Directiva 002-2021-PCM/SGTD, arts. 7, 8 y 14 | N CVD de 16 dígitos en grupos de cuatro; glosa al pie de cada página en Courier. El frontend mantiene el CVD de 8 caracteres y deja el de 16 dígitos configurable. | Ayuda con hoja de ejemplo de oficio o carta (servicios-publicos.md, §3 y §9; components/casilla-estados-y-privacidad.md, §6). |
| Mensajes de verificación | Directiva 002-2021-PCM/SGTD, art. 11.2 d | N «CVD no válido», «El documento no se encuentra disponible», «El servicio no está accesible». | Alertas de estado de Verifica, con el conjunto actual o directiva configurable (servicios-publicos.md, §4 y §9). |
| Acuse de recibo y avisos de la casilla | Ley 31736, arts. 3 j, 4.3, 4.4 y 5.4 a 5.7 | N Existe el acuse (cinco primeros días hábiles) y los avisos al correo y al celular. IP El efecto de no confirmar. UX Mostrar solo lo que el servicio acredita con fecha. | NotificationStatus (gov-desk), apagado por defecto; ver components/casilla-estados-y-privacidad.md, §3. |
| Accesibilidad de formularios | Res. SGTD 001-2025-PCM/SGTD; DS 029-2021-PCM, art. 24 b | N WCAG 2.2 A y AA. | Ver «Accesibilidad y adaptación» y el estándar. |
Referencias legales en pantalla: solo cuando la norma las exige o ayudan a la persona (glosa, aviso de privacidad, términos, mensajes de verificación, la autorización de notificar por correo), con texto comprensible y sin transcribir artículos. No citar normas que no estén en estado Oficial en el documento central.
Accesibilidad y adaptación
-
Botones de solo icono: siempre
Button variant="ghost" size="icon"(hover tenue--sgd-icon-hover, foco visible y tooltip con suaria-label); no armar<button>con clases propias. Para tamaños menores,!size-6/!size-7con!min-h-0 !min-w-0.TreeToggle(ui/tree-toggle.tsx) es la flecha de contraer y expandir de los árboles (Seguimiento, referencias, ejemplo del Design System); el botón de borrar deSearchInput, el de cerrar del recorrido guiado y el del panel de descarga usan el mismo componente. Los que quedan con estilo propio son el cierre de los diálogos (DialogCloseButton) y las flechas de los botones divididos de la cabecera del documento, que comparten las clases deButton. -
Campo de búsqueda:
SearchInput(ui/search-input.tsx) es unInputcon la lupa a la izquierda dentro del campo (color de acento con el foco) y, cononCleary texto, un botón «×» a la derecha para borrar (devuelve el foco al campo; nombre accesible «Borrar búsqueda»). Rolsearchboxcontype="text": untype="search"vacía el campo con Escape, y dentro de un modal Escape debe cerrarlo. Lo usan los modales de búsqueda de entidades (EntityPickerDialog: dependencia, personal, ciudadano, organización…) y el buscador de referencias; usarlo en los buscadores nuevos en lugar de armar la lupa a mano. Los selectores con búsqueda dentro del campo (SearchableCombobox) no llevan lupa: su flecha indica que son una lista. -
Prioridad con color:
PriorityChip(ui/priority-chip.tsx) muestra el nombre con un punto y un fondo suave del color de la propia prioridad (catálogo, administrable en /admin/prioridades; respaldo por nombre: Normal azul, Urgente ámbar, Muy urgente rojo). El texto siempre queda oscuro y visible, de modo que el significado no depende solo del color. En selectores,EntityComboboxaceptagetSwatch(punto de color en la lista y en el campo cerrado), que usaPriorityCombobox. Usar estos componentes en lugar de colores fijos por pantalla. -
Reordenación de filas:
RowReorderControls(ui/row-reorder-controls.tsx) reúne el asa, sensores dnd-kit de teclado/puntero y botones Subir/Bajar de 24 px, con nombres y anuncios en español. Usado por destinatarios/V°B° y ejemplo en «Accesibilidad». Disposición uniforme: el número de orden va primero, en un círculo, y pegados a él el asa y las flechas, todo en la misma celda o fila a la izquierda (sin una columna de número aparte, que separa el número de sus controles). Mantener una única operación de modelo para los tres medios; teclado y clic sin arrastre se verifican por separado. Vercomponents/formularios-documentos.mdy el lote 1 del diagnóstico. -
Etiquetas administrativas:
FieldLabel htmlFory eliddel control deben coincidir; usaruseIdpara varias instancias. La etiqueta visible da el nombre del campo, sin reemplazarla por un nombre ARIA genérico.DateFieldnombra el calendario emergente y admitecalendarLabelcontextual. -
Objetivo WCAG AA: texto normal ≥4,5:1, texto grande e indicadores de componente ≥3:1. Verificar claro y oscuro para cada paleta antes de dar por cerrada una pantalla.
-
Navegación por teclado y Escape en menús y diálogos. Foco visible incluso cuando el control tiene solo icono. Nombre accesible en botones de icono;
aria-livepara resultados dinámicos cuando sea necesario. -
Los tooltips de iconos conservan 8 px de margen respecto al viewport y al diálogo que contiene el disparador. Si el lado preferido no cabe, pasan al opuesto o a uno perpendicular; Radix posiciona el contenido y orienta la flecha. El texto largo se ajusta al espacio sin ensanchar el modal.
-
No depender solo de hover, color o posición para identificar estado. Respetar
prefers-reduced-motion. -
En móvil, apilar filtros sin perder sus etiquetas, mantener acciones alcanzables y confinar el scroll horizontal a tablas o a la tira de bandejas. Desde menos de 1280 px, la navegación superior pasa al panel móvil para que no desborde. No truncar las etiquetas de bandejas; permitir leerlas mediante la tira desplazable. Comprobar anchos de 375, 768 y 1280 px y zoom del navegador.
Flujo Figma a código
Si se proporciona un frame de Figma Design accesible por MCP: leer contexto y captura del nodo exacto, identificar tokens y componentes existentes, implementar con las primitivas del SGD y verificar el resultado en el navegador. Si solo hay una exportación de diseño, tratar su código y capturas como referencia visual, registrar los estados ausentes y no atribuirles especificaciones que no existen. Los estilos de pantallas nuevas se incorporan a src/components/ui/ y a tokens, no a copias locales.
Dashboard de impacto ambiental
La pestaña ambiental usa los mismos paneles, tipografía e iconos del SGD. Sus cifras actuales son ilustrativas, no datos operativos: 9 470 documentos entre enero y setiembre de 2026, 5 hojas por documento y 5 g por hoja. Las tarjetas, series mensuales y metodología derivan de esa misma base y muestran el redondeo solo al final. El anillo representa la distribución trimestral de documentos; no mezcla hojas, CO₂ y árboles en un índice sin unidad. El diálogo reproduce los cuatro factores de la captura: 5 hojas por documento, 5 g por hoja, un árbol por cada 8 500 hojas y 4,5 kg de CO₂ por kg de papel. Por ello, el valor ilustrativo de árboles es 5,6, coherente con 47 350 hojas. La captura de la tarjeta mostraba 27,8 con un factor distinto; se priorizó la metodología indicada por el usuario. Estos factores no están validados ni son configurables todavía en el SGD. Las equivalencias de agua, energía, superficie reforestada y viajes de la captura no se muestran porque la referencia no aporta factores verificables para calcularlas. Antes de usar esta vista como informe, conectar datos reales y validar los factores con el área responsable.
Alcance de la aplicación
Aplicado a tokens de superficie y geometría, navegación superior y lateral, primitivas compartidas y la pantalla Emisión de documentos. Se normalizaron también los tamaños de iconos y el texto funcional pequeño en pantallas de usuario y administración. Los módulos con formularios, tablas o diálogos locales aún requieren migrar reglas particulares a las primitivas compartidas al modificarlos; no cambiar sus flujos ni datos durante esa migración.
Accesibilidad: anchos y datos equivalentes (15-oct-2026)
- Separadores existentes: clic/toque o Espacio abre
WidthControlsmediante Popover. Misma confirmación, límites y persistencia que arrastre/teclado; sin duplicar selectores de columnas. Escape restaura foco. Vercomponents/tables.md§9. - Comparativa diaria: «Ver datos diarios» abre el Dialog compartido con fechas y valores exactos de las series visibles, sin agregación semanal ni redondeos. La región larga recibe foco y permite scroll por teclado, con footer visible. El filtro de leyenda no reduce el contraste del texto de la serie oculta; tachado y aria-pressed distinguen el estado.
- Evidencia y limitaciones: diagnóstico compartido §9; las muestras de desarrollo no sustituyen las pantallas protegidas ni NVDA.
| Hoja inferior | Sheet side="bottom" (ui/sheet.tsx, estilos .sgd-sheet-grip, .sgd-sheet-pill y .sgd-sheet-bottom en globals.css): lleva un tirador de rayita horizontal de 40 × 5 px arriba, con zona táctil de 28 px, como el de WhatsApp o Adobe. Se arrastra hacia abajo para cerrar (más de 56 px o gesto rápido) y hacia arriba para ampliar (data-size="alta", hasta 92 dvh; normal hasta 60 dvh); la hoja sigue al dedo al bajar. Sin arrastrar (WCAG 2.5.7): el tirador es un botón con foco (Enter o Espacio alternan el tamaño, ↑ amplía, ↓ reduce y, si ya es normal, cierra). Ejemplo en /design-system/componentes (sección de diálogos: «Hoja inferior · con tirador»). Misma pieza en las hojas Páginas y Más del visor de PDF en celular. |
| Diálogo como hoja en celular | DialogContent mobileSheet (ui/dialog.tsx, estilos .sgd-dialog-sheet en globals.css): con menos de 640 px se muestra como hoja inferior (pegada abajo, a todo el ancho, esquinas superiores redondeadas, entrada desde abajo, área segura y tirador de rayita para cerrar arrastrando); desde 640 px es el diálogo centrado. Opcional y apagado por defecto. Ver components/dialogs.md y el ejemplo «Diálogo como hoja en celular» en /design-system/componentes. |