Steven
Steven9 min de lectura

Rediseñar el dashboard en torno a un gráfico de onda

La GeekBye v1.8.2 transformó el dashboard de un control remoto de grabación a una vista de analítica de solo lectura — una tira de estadísticas y un gráfico de onda de 7 días. Ambos elementos característicos fueron segundos borradores, publicados a los veinte minutos de sus primeros borradores, la misma tarde.

Ingeniería
Diseño
Dashboard
Lanzamientos de GeekBye
Rediseñar el dashboard en torno a un gráfico de onda

Algunas releases añaden una feature. La GeekBye v1.8.2 sobre todo eliminó una — y la eliminación es la historia. En una sola tarde de febrero de 2026, dieciocho commits convirtieron la pantalla de inicio del dashboard de un control remoto de grabación en una vista de analítica de solo lectura: cuatro estadísticas y un gráfico de actividad. Por el camino publicó un gráfico de barras que vivió veintidós minutos, una rejilla de tarjetas de estadísticas que vivió veinte y una onda SVG hecha a mano que reemplazó a ambos. Toda la búsqueda queda preservada en las marcas de tiempo de los commits, que es el mejor tipo de documentación de diseño que existe.

El dashboard dejó de ser un control remoto

Antes de esta release, la pantalla de inicio del dashboard era un panel de control. Se encabezaba con una tarjeta hero — un gran widget de grabación con una insignia LIVE, botones de Pausar/Reanudar/Detener, manchas de degradado y un hook useSessionState que lo cableaba todo con la grabadora. El dashboard intentaba ser dos cosas a la vez: el sitio donde miras tus reuniones y el sitio donde manejas la grabadora. Dos productos, una pantalla, compitiendo en silencio.

La v1.8.2 eligió uno. Borró la tarjeta hero y el cableado de useSessionState — incluyendo un efecto que te llevaba automáticamente a la página de detalle de una reunión en el instante en que terminaba una sesión, que es justo esa clase de salto «servicial» que sorprende a la gente en mitad de lo que está haciendo. Iniciar y ocultar la grabadora se trasladó a un simple botón de la navbar (un botón reaprovechado que perdió cerca de cien líneas al pasar de controlador de sesión a interruptor de encendido/apagado), respaldado por un nuevo manejador IPC navbar:hide. Lo que quedó fue un dashboard que hace una sola cosa: mostrarte lo que has grabado. Solo lectura. Tranquilo.

Hay un pequeño bug, muy humano, en esa transición que vale la pena señalar, porque es de esas cosas que un rediseño introduce sin hacer ruido y que un buen ojo detecta esa misma hora. Los dos botones nuevos de la barra lateral — Iniciar y Ocultar — salieron con el mismo icono genérico de rejilla, así que eran visualmente idénticos. Doce minutos después, un follow-up le dio a Iniciar un icono de play, le dio a Ocultar un icono de ojo tachado y tiñó Ocultar de ámbar, para que «hacer que la app desaparezca» se lea como una acción deliberada y no como el gemelo neutro de «iniciar». Los iconos son copy. Dos botones que se ven igual dicen lo mismo, y estos no significaban lo mismo.

El gráfico de barras que vivió veintidós minutos

Aquí está la parte que me encanta, y es completamente legible desde el git log. A las 16:29:34 aterrizó el primer borrador del rediseño: un gráfico de actividad de 7 días dibujado como barras — columnas animadas, una altura mínima para que los días diminutos siguieran siendo visibles, un trazo tenue de 2 píxeles para los días con cero. Razonable. Convencional. El tipo de gráfico al que recurres sin pensar.

A las 16:51:21 — veintidós minutos después — fue borrado. El commit de reemplazo dice exactamente lo que hizo: «replace bar chart with smooth wave area chart for 7-day activity» (reemplazar el gráfico de barras por un gráfico de área de onda suave para la actividad de 7 días). Y a las 16:52:21, un minuto más tarde, otro commit le quitó la tarjeta redondeada y el borde que rodeaban la onda, «for cleaner look» (para un aspecto más limpio).

¿Por qué? Los commits solo dicen qué cambió, así que el porqué es una lectura — pero la forma de los datos lo hace obvio. Esta es una herramienta donde un usuario típico tiene cero, una o dos reuniones en un día cualquiera. Siete barras, la mayoría de 2 píxeles de alto, parecen un aparcamiento casi vacío. Los mismos siete números dibujados como un área rellena continua parecen una tendencia — una onda suave que sube donde la semana estuvo ocupada. No se falseó nada; los valores en el eje y son idénticos. El rediseño simplemente eligió la codificación que permite que datos escasos y honestos se lean como una forma en vez de como una ausencia.

Las estadísticas recibieron el mismo trato en el mismo reloj. El primer borrador (16:29) puso cuatro números en una rejilla de tarjetas de 2×4. A las 16:49 la rejilla se colapsó en una única tira de estadísticas en línea — una sola fila con borde y divisores finísimos, tipografía más pequeña, un contenedor en vez de cuatro. Cinco cajas en la pantalla (cuatro tarjetas más una tarjeta de gráfico) pasaron a ser dos (una tira y una onda). El siguiente PR añadió un toque honesto más: la etiqueta «Total Time» pasó a ser «Time in Meetings» (Tiempo en reuniones), porque total-de-qué era una pregunta razonable que nadie debería tener que hacerse.

Veinte minutos, del primer borrador al final, todo dentro de un mismo pull request. Si aquello se hubiera aplastado en un único commit «redesign dashboard», la búsqueda sería invisible. Como no fue así, puedes ver a un diseñador converger en tiempo real.

La onda, mecánicamente

Aquí no hay ninguna librería de gráficos. La onda es un SVG en línea construido en JSX, y merece un vistazo porque es una receta pequeña y honesta que puedes robar para cualquier sparkline.

El suavizado es el truco. Para cada par de puntos adyacentes, el path usa un segmento cubic-bezier cuyos dos puntos de control se sitúan en el punto medio horizontal entre ellos — cpx = (prev.x + curr.x) / 2 — con los puntos de control mantenidos a la altura propia de cada extremo. Ese es el clásico suavizado de tangente plana: la curva pasa suavemente por cada punto de datos sin sobrepasar jamás por encima del valor más alto ni por debajo del más bajo, cosa que sí haría un spline Catmull-Rom ingenuo. Para un gráfico sobre número de reuniones, «no dibujar nunca un bulto que implique un valor que no ocurrió» no es un detalle bonito; es corrección. El área rellena es la misma curva cerrada por abajo y pintada con un degradado vertical (cian, desvaneciéndose del 30% a casi nada), y la línea se dibuja sola con una animación pathLength de framer-motion, de izquierda a derecha.

Bajo el SVG está la fontanería de datos, y es la heroína silenciosa. Un nuevo método getAggregateStats() en el repositorio de transcripciones ejecuta tres prepared statements contra la tabla local de SQLite transcript_sessions: totales de todo el tiempo (recuento, duración sumada, duración media), un recuento móvil de siete días y un bucket por día con GROUP BY date(created_at). Luego — y este es el detalle que hace robusto al gráfico — un pequeño bucle de JavaScript recorre los últimos siete días naturales y rellena cada día que la query no devolvió, metiendo un cero. Por eso el gráfico tiene garantizados exactamente siete puntos, siempre.

Esa garantía es lo que hace que los casos límite desaparezcan en vez de necesitar comprobaciones desperdigadas por toda la vista. ¿Una semana vacía? Siete ceros, y un Math.max(count, 1) en el denominador mantiene la línea plana abajo en vez de dividir por cero. ¿Un único punto de datos que haría que la fórmula de espaciado en x i / (n − 1) produjera NaN? No puede pasar — el repositorio nunca emite menos de siete. Las etiquetas de los días de la semana incluso parsean cada bucket a T12:00:00 en lugar de la medianoche pelada, para que una cadena YYYY-MM-DD no se escurra al día anterior en una zona horaria con UTC negativo. Arregla la forma de los datos en el origen y el código de renderizado puede permitirse ser ingenuo a propósito.

Todo se queda en la máquina. La query de estadísticas lee la base de datos local, vuelve a través de un canal IPC tipado transcript:get-stats y se anima en cuatro números que cuentan hacia arriba al montarse. Nada de tu historial de reuniones sale del portátil para dibujar este gráfico — lo cual, para una herramienta que graba tus conversaciones, es la única manera aceptable de construir una vista de analítica.

Un bug más, porque los rediseños los sacan a la luz

Empaquetado en la misma release iba un arreglo que no tenía nada que ver con el dashboard y todo que ver con el tipo de deuda con la que tropieza un rediseño. El estilo de la barra de desplazamiento oscura de la app había derivado en dos definiciones CSS en competencia de la misma clase — una más antigua, morada, y otra más nueva, blanca sobre oscuro — y cuál ganaba dependía del orden de la cascada. Peor aún, solo los elementos que se acordaban de añadir la clase recibían algún estilo; todo lo demás caía de vuelta a la barra de desplazamiento clara por defecto, y las barras de desplazamiento horizontales nunca tuvieron estilo porque las reglas viejas fijaban solo un ancho, nunca un alto. El arreglo borró ambas definiciones, aplicó estilo a la barra de desplazamiento de forma global en todos los elementos y quitó la clase ya muerta de los diez componentes que la venían arrastrando. Es un diff de dos líneas repetido diez veces — el impuesto poco glamuroso de haber dado estilo a lo mismo dos veces y dejar sobrevivir a las dos.

Tres cosas que nos enseñó esta release

  1. Restar para enfocar. El dashboard mejoró haciendo menos — perdiendo los controles de grabación que nunca necesitó y convirtiéndose en una cosa clara. Una pantalla que es a la vez visor y mando a distancia son dos medios-productos; elige uno y mueve el otro a donde le corresponde.
  2. Elige la codificación que tus datos merecen. Los recuentos escasos se leen como ausencia en barras y como tendencia en un gráfico de área, a partir de números idénticos. Eso no es maquillaje — es elegir la forma honesta que permite comunicar a datos reales y escasos.
  3. Garantiza la forma de los datos aguas arriba. El bucle de relleno-hasta-siete es la razón por la que el código del gráfico no tiene comprobaciones de null desperdigadas: la división por cero, el NaN de un solo punto y los días que faltan desaparecen todos porque la query promete exactamente siete buckets. El renderizado robusto empieza una capa más abajo.

Para el capítulo anterior de la historia v1, cuatro releases en veintiséis horas (v1.7.6–v1.8.1); y para todo el arco, la anatomía de publicar software hasta la perfección.