Steven
Steven7 хв читання

Перепроєктування дашборда навколо одного хвильового графіка

GeekBye v1.8.2 перетворив дашборд із пульта керування записом на аналітичний вид тільки-для-читання — смуга статистики та 7-денний хвильовий графік. Обидва фірмові елементи були другими чернетками, випущеними протягом двадцяти хвилин після перших, того самого дня по обіді.

Інженерія
Дизайн
Дашборд
Релізи GeekBye
Перепроєктування дашборда навколо одного хвильового графіка

Деякі релізи додають фічу. GeekBye v1.8.2 переважно одну видалив — і це видалення і є історією. За один день по обіді в лютому 2026 вісімнадцять commits перетворили головну дашборда з пульта керування записом на аналітичний вид тільки-для-читання: чотири статистики й один графік активності. Дорогою він випустив стовпчиковий графік, що прожив двадцять дві хвилини, сітку карток статистики, що прожила двадцять, і саморобну хвилю в SVG, яка замінила обидві. Увесь цей пошук збережено в таймстампах commits, а це найкращий різновид проєктної документації, який лише буває.

Дашборд перестав бути пультом

До цього релізу головна дашборда була панеллю керування. Її відкривала hero-картка — великий віджет запису з бейджем LIVE, кнопками Pause/Resume/Stop, градієнтними плямами й хуком useSessionState, що зв'язував усе це з рекордером. Дашборд намагався бути двома речами водночас: місцем, де ти дивишся свої зустрічі, і місцем, звідки ти керуєш рекордером. Два продукти, один екран, що тихо конкурують.

v1.8.2 вибрав одне. Він видалив hero-картку й усю обв'язку useSessionState — включно з ефектом, який автоматично перекидав тебе на сторінку деталей зустрічі в момент завершення сесії, а це рівно той сорт «корисного» стрибка, що збиває людей посеред роботи. Запуск і приховування рекордера переїхали в звичайний тумблер навбара (перероблена кнопка, що схудла приблизно на сотню рядків дорогою від контролера сесії до вимикача on/off), спираючись на новий IPC-обробник navbar:hide. Лишилося те, що робить одне: показує тобі, що ти записав. Тільки для читання. Спокійно.

У цьому переході ховається маленький, людський баг, про який варто сказати, бо це якраз те, що редизайн тихо привносить, а добре око ловить у ту саму годину. Дві нові кнопки бічної панелі — Start і Hide — вийшли з однією й тією самою дженериковою іконкою сітки, тож були візуально ідентичні. Дванадцять хвилин по тому доробка дала Start іконку play, дала Hide іконку перекресленого ока й підфарбувала Hide бурштиновим, щоб «прибрати застосунок з очей» читалося як навмисна дія, а не нейтральний близнюк «старту». Іконки — це теж текст. Дві кнопки, що виглядають однаково, кажуть одне й те саме, а ці не значили одного й того самого.

Стовпчиковий графік, що прожив двадцять дві хвилини

Ось частина, яку я обожнюю, і вона повністю читається з git-логу. О 16:29:34 приземлилася перша чернетка редизайну: 7-денний графік активності, намальований стовпчиками — анімовані колонки, мінімальна висота, щоб крихітні дні лишалися видимими, 2-піксельний тьмяний оцупок для нульових днів. Розумно. Звично. Такий графік, до якого тягнешся не замислюючись.

О 16:51:21 — двадцять дві хвилини по тому — його видалили. Замінний commit каже рівно, що він зробив: «replace bar chart with smooth wave area chart for 7-day activity». А о 16:52:21, на хвилину пізніше, ще один commit зняв заокруглену картку й рамку навколо хвилі — «for cleaner look».

Чому? Commits кажуть лише, що змінилося, тож чому — це прочитання, але форма даних робить його очевидним. Це інструмент, де в типового користувача нуль, одна або дві зустрічі будь-якого окремого дня. Сім стовпчиків, більшість заввишки 2 пікселі, виглядають як майже порожня парковка. Ті самі сім чисел, намальовані як суцільна заповнена область, виглядають як тренд — плавна хвиля, що підіймається там, де тиждень був завантажений. Нічого не підробили; значення по y ідентичні. Редизайн просто вибрав кодування, яке дозволяє розрідженим, чесним даним читатися як форма, а не як відсутність.

Статистика дістала те саме поводження за тим самим годинником. Перша чернетка (16:29) помістила чотири числа в сітку карток 2×4. О 16:49 сітка склалася в одну вбудовану смугу статистики — єдиний обрамлений рядок із волосяними роздільниками, дрібнішим шрифтом, одним контейнером замість чотирьох. П'ять коробок на екрані (чотири картки плюс картка графіка) стали двома (смуга й хвиля). Наступний PR додав ще один чесний штрих: підпис «Total Time» (Усього часу) став «Time in Meetings» (Час на зустрічах), бо всього-чого було справедливим питанням, якого ніхто не мусив би ставити.

Двадцять хвилин, від першої чернетки до фіналу, усе всередині одного pull request. Якби це зсквошили в один commit «redesign dashboard», пошук був би невидимим. Оскільки не зсквошили, ти можеш спостерігати, як дизайнер сходиться до рішення в реальному часі.

Хвиля, з погляду механіки

Тут немає жодної графічної бібліотеки. Хвиля — це вбудований SVG, зібраний у JSX, і на неї варто глянути, бо це маленький, чесний рецепт, який ти можеш поцупити для будь-якого sparkline.

Згладжування — ось увесь трюк. Для кожної пари сусідніх точок шлях використовує сегмент кубічної кривої Безьє, дві контрольні точки якого сидять у горизонтальній середині між ними — cpx = (prev.x + curr.x) / 2 — при цьому контрольні точки тримаються на висоті свого кінця. Це класичне згладжування з плоскою дотичною: крива плавно проходить крізь кожну точку даних, ніколи не вистрілюючи вище найвищого чи нижче найнижчого значення, що зробив би наївний сплайн Катмулла-Рома. Для графіка про кількість зустрічей «ніколи не малюй горбок, що натякає на значення, якого не було» — не оздоба; це коректність. Заповнена область — та сама крива, замкнена по низу й зафарбована вертикальним градієнтом (ціан, що згасає від 30% майже до нуля), а лінія сама себе малює анімацією pathLength із framer-motion, зліва направо.

Під SVG — водогін даних, і він тихий герой. Новий метод getAggregateStats() у репозиторії транскриптів ганяє три підготовлені запити по локальній таблиці SQLite transcript_sessions: підсумки за весь час (кількість, сумарна тривалість, середня тривалість), ковзний лік за сім днів і кошик на день GROUP BY date(created_at). Потім — і це та деталь, що робить графік стійким — маленький цикл на JavaScript проходить по останніх семи календарних днях і дозаповнює кожен день, який запит не повернув, вштовхуючи нуль. Графік тому гарантовано має рівно сім точок, завжди.

Саме ця гарантія змушує крайні випадки зникнути, замість того щоб розкидати перевірки по всьому вигляду. Порожній тиждень? Сім нулів, а Math.max(count, 1) у знаменнику тримає лінію плоскою внизу, а не ділить на нуль. Одна точка даних, через яку формула кроку по осі x i / (n − 1) видала б NaN? Не може статися — репозиторій ніколи не видає менше семи. Підписи днів тижня навіть парсять кожен кошик на T12:00:00, а не на голу північ, щоб рядок YYYY-MM-DD не сковзнув на попередній день у часовому поясі з від'ємним UTC. Полагодь форму даних біля джерела — і код рендерингу може бути наївним навмисно.

Усе це лишається на машині. Запит статистики читає локальну базу, повертається через типізований IPC-канал transcript:get-stats і анімується в чотири числа, що відлічують угору, при монтуванні. Ніщо з твоєї історії зустрічей не покидає ноутбук, щоб намалювати цей графік — що для інструмента, який записує твої розмови, єдиний прийнятний спосіб побудувати аналітичний вид.

Ще один баг, бо редизайни витягають їх на світло

У той самий реліз було вкладено фікс, що не мав нічого спільного з дашбордом і все спільне — з тим родом боргу, об який редизайн спотикається. Стилізація темного скролбара в застосунку роз'їхалася на два конкурентні CSS-визначення одного класу — старе фіолетове й нове біле-на-темному — і те, яке перемагало, залежало від порядку в каскаді. Гірше того, стилізувалися лише ті елементи, що не забули додати клас; усе інше відкочувалося до дефолтного світлого скролбара, а горизонтальні скролбари не стилізувалися ніколи, бо старі правила задавали лише ширину, але не висоту. Фікс видалив обидва визначення, стилізував скролбар глобально на кожному елементі й прибрав тепер-мертвий клас із десяти компонентів, що його тягали. Це дворядковий дифф, повторений десять разів — негламурний податок за те, що одне й те саме було стилізовано двічі, а обидві версії лишили живими.

Три речі, яких нас навчив цей реліз

  1. Віднімай, щоб сфокусуватися. Дашборд став кращим, роблячи менше — втративши керування записом, яке йому ніколи не було потрібне, і ставши однією ясною річчю. Екран, що водночас і переглядач, і пульт, — це два напівпродукти; вибери один, а інший перенеси туди, де його місце.
  2. Вибирай кодування, на яке заслуговують твої дані. Розріджені лічильники читаються як відсутність у стовпчиках і як тренд на area chart — з однакових чисел. Це не підтасовка; це вибір чесної форми, яка дає справжнім, худим даним щось повідомити.
  3. Гарантуй форму даних вище за потоком. Цикл дозаповнення до семи — ось чому в коді графіка немає розкиданих перевірок на null: ділення на нуль, NaN на одній точці й пропущені дні зникають, бо запит обіцяє рівно сім кошиків. Стійкий рендеринг починається шаром нижче.

Про попередній розділ історії v1 — чотири релізи за двадцять шість годин (v1.7.6–v1.8.1); а про всю дугу — анатомію доставки програмного забезпечення до досконалості.

Схожі статті

Сторінка логіна і Є демо
Steven
Steven6 хв читання

Сторінка логіна і Є демо

GeekBye v1.7.5 додав скриншот продукту на сторінку логіна й видалив його того ж дня — перезібравши натомість демо зі справжніх компонентів. Плюс: користувач, який виявився швидшим за OCR, і як насправді виглядають 25 стильових commitів за один день.

Інженерія
Дизайн
UX
Одна CSS-змінна, п'ять раундів рев'ю та ланцюжок інструментів Swift, що збрехав
Steven
Steven6 хв читання

Одна CSS-змінна, п'ять раундів рев'ю та ланцюжок інструментів Swift, що збрехав

GeekBye v2.0.7 зробив увесь оверлей регульовано напівпрозорим — що звучить як однорядкова зміна CSS і абсолютно нею не було. Справжня історія — про те, що виловило код-рев'ю: дві поверхні, які відмовлялися згасати, панель запису, що виглядала неправильно за тієї самої прозорості, і скомпільований бінарник, який стрибнув на 672 байти, бо наша власна документація підказала рецензенту неправильну версію Swift.

Інженерія
Дизайн
Збірка
Спокійне програмне забезпечення: як ми прибрали миготливий перемикач і навчили чат казати, у якому він режимі
Steven
Steven6 хв читання

Спокійне програмне забезпечення: як ми прибрали миготливий перемикач і навчили чат казати, у якому він режимі

Два невеликі релізи GeekBye без гучних функцій — лише перемикач у налаштуваннях, який перестав миготіти, і чат-асистент, який нарешті каже, чи відповів він у режимі зустрічі, чи в режимі кодування. Ось скільки насправді коштує «спокійне програмне забезпечення», по одній деталі за раз.

Продукт
Дизайн
Інженерія