
Thiết kế lại Dashboard xoay quanh một biểu đồ sóng duy nhất
GeekBye v1.8.2 biến dashboard từ một chiếc điều khiển từ xa cho việc ghi âm thành một khung phân tích chỉ-đọc — một dải thống kê và một biểu đồ sóng 7 ngày. Cả hai thành phần đặc trưng đều là bản nháp thứ hai, được ship trong vòng 20 phút sau bản nháp đầu, trong cùng một buổi chiều.
Có những bản phát hành thêm một tính năng. GeekBye v1.8.2 phần lớn là bỏ đi một tính năng — và chính việc bỏ đi ấy là câu chuyện. Trong một buổi chiều tháng Hai 2026, mười tám commit biến trang chủ dashboard từ một chiếc điều khiển từ xa cho việc ghi âm thành một khung phân tích chỉ-đọc: bốn con số thống kê và một biểu đồ hoạt động. Dọc đường nó đã ship một biểu đồ cột sống 22 phút, một lưới thẻ thống kê sống 20 phút, và một sóng SVG tự tay dựng thay thế cả hai. Toàn bộ quá trình tìm tòi được lưu giữ trong các timestamp của commit, thứ tài liệu thiết kế tốt nhất trên đời.
Dashboard thôi làm điều khiển từ xa
Trước bản phát hành này, trang chủ dashboard là một bảng điều khiển. Nó mở đầu bằng một hero card — một widget ghi âm to đùng với huy hiệu LIVE, các nút Pause/Resume/Stop, những mảng gradient, và một hook useSessionState đấu nối tất cả vào bộ ghi âm. Dashboard đang cố làm hai việc cùng lúc: nơi bạn nhìn các cuộc họp của mình, và nơi bạn điều khiển bộ ghi âm. Hai sản phẩm, một màn hình, lặng lẽ cạnh tranh.
v1.8.2 chọn một. Nó xóa hero card và toàn bộ đấu nối useSessionState — bao gồm cả một effect tự động đưa bạn tới trang chi tiết của một cuộc họp ngay khoảnh khắc phiên kết thúc, mà đó đúng là kiểu nhảy trang "tử tế" khiến người ta giật mình giữa dòng công việc. Việc bắt đầu và ẩn bộ ghi âm được dời ra một toggle mộc mạc trên navbar (một nút được đổi mục đích, rụng đi chừng trăm dòng khi từ bộ điều khiển phiên thành một công tắc bật/tắt), có một IPC handler mới navbar:hide đỡ phía sau. Thứ còn lại là một dashboard chỉ làm một việc: cho bạn xem những gì bạn đã ghi. Chỉ-đọc. Yên tĩnh.
Trong bước chuyển này có một con bug nhỏ, rất "người", đáng nêu ra, vì nó chính là loại thứ mà một cuộc thiết kế lại lặng lẽ mang vào và một con mắt tinh sẽ bắt được ngay trong cùng giờ đó. Hai nút mới trên sidebar — Start và Hide — được ship với cùng một icon lưới chung chung, nên nhìn hệt nhau. Mười hai phút sau, một bản chỉnh theo sau cho Start một icon play, cho Hide một icon mắt-gạch, và nhuộm Hide màu hổ phách, để "làm ứng dụng biến đi" đọc thành một hành động có chủ ý chứ không phải một bản sao trung tính của "bắt đầu". Icon chính là chữ (copy). Hai nút trông giống nhau nói cùng một điều, mà hai nút này lại không có nghĩa giống nhau.
Biểu đồ cột sống 22 phút
Đây là phần tôi mê, và nó đọc được trọn vẹn từ git log. Vào lúc 16:29:34, bản nháp đầu của cuộc thiết kế lại đáp xuống: một biểu đồ hoạt động 7 ngày vẽ bằng các cột — những cột có hoạt ảnh, một chiều cao tối thiểu để những ngày bé xíu vẫn thấy được, một mẩu cột mờ cao 2 pixel cho những ngày bằng không. Hợp lý. Quy ước. Loại biểu đồ bạn với tay lấy mà chẳng cần nghĩ.
Vào lúc 16:51:21 — 22 phút sau — nó bị xóa. Commit thay thế nói đúng những gì nó đã làm: "replace bar chart with smooth wave area chart for 7-day activity". Và vào lúc 16:52:21, một phút sau đó, một commit khác lột bỏ cái thẻ bo góc và đường viền quanh sóng, "for cleaner look".
Vì sao? Các commit chỉ nói cái gì thay đổi, nên vì sao là một cách đọc — nhưng hình dạng của dữ liệu khiến nó hiển nhiên. Đây là một công cụ mà một người dùng điển hình có không, một, hoặc hai cuộc họp trong bất kỳ ngày nào. Bảy cái cột, phần lớn chỉ cao 2 pixel, trông như một bãi đỗ xe gần như trống trơn. Cũng bảy con số ấy vẽ thành một vùng tô liền mạch lại trông như một xu hướng — một con sóng dịu nhô lên đúng chỗ tuần đó bận rộn. Không có gì bị làm giả; các giá trị y y hệt nhau. Cuộc thiết kế lại chỉ đơn giản chọn cách mã hóa cho phép dữ liệu thưa và trung thực đọc thành một hình dạng thay vì thành sự vắng mặt.
Các con số thống kê nhận cùng cách xử lý trên cùng chiếc đồng hồ. Bản nháp đầu (16:29) đặt bốn con số vào một lưới thẻ 2×4. Vào lúc 16:49, cái lưới xẹp lại thành một dải thống kê inline duy nhất — một hàng có viền, chia bằng những đường mảnh như sợi tóc, cỡ chữ nhỏ hơn, một container thay vì bốn. Năm cái hộp trên màn hình (bốn thẻ cộng một thẻ biểu đồ) thành hai (một dải và một sóng). PR kế tiếp thêm một nét trung thực nữa: nhãn "Total Time" thành "Time in Meetings", vì tổng-của-cái gì là một câu hỏi chính đáng mà lẽ ra không ai phải hỏi.
Hai mươi phút, từ bản nháp đầu đến bản cuối, tất cả gói trong một pull request. Nếu chúng bị squash thành một commit "redesign dashboard" duy nhất, quá trình tìm tòi sẽ vô hình. Vì chúng không bị gộp, bạn có thể xem một nhà thiết kế hội tụ theo thời gian thực.
Con sóng, xét về cơ chế
Ở đây không có thư viện biểu đồ nào. Con sóng là một SVG inline dựng trong JSX, và đáng để ngó qua vì nó là một công thức nhỏ, trung thực mà bạn có thể chôm cho bất kỳ sparkline nào.
Việc làm mượt là mấu chốt. Với mỗi cặp điểm kề nhau, đường path dùng một đoạn cubic-bezier có hai điểm điều khiển nằm ở trung điểm theo phương ngang giữa chúng — cpx = (prev.x + curr.x) / 2 — với các điểm điều khiển được giữ ở đúng chiều cao của từng đầu. Đó là kiểu làm mượt tiếp-tuyến-phẳng kinh điển: đường cong lướt qua từng điểm dữ liệu mà không bao giờ vọt lên trên giá trị cao nhất hay xuống dưới giá trị thấp nhất — điều mà một spline Catmull-Rom ngây thơ sẽ làm. Với một biểu đồ về số lượng cuộc họp, "không bao giờ vẽ một cái bướu ám chỉ một giá trị chưa từng xảy ra" không phải là nét duyên; nó là tính đúng đắn. Vùng tô là cùng đường cong ấy khép lại dọc đáy và phết một dải gradient dọc (màu cyan, nhạt dần từ 30% xuống gần như không còn gì), còn đường nét thì tự vẽ mình lên bằng một hoạt ảnh pathLength của framer-motion, từ trái sang phải.
Bên dưới SVG là hệ ống dẫn dữ liệu, và đó là người hùng thầm lặng. Một phương thức mới getAggregateStats() trên transcript repository chạy ba prepared statement lên bảng SQLite transcript_sessions cục bộ: các tổng toàn thời gian (số lượng, tổng thời lượng, thời lượng trung bình), một bộ đếm bảy-ngày trượt, và một bucket theo từng ngày bằng GROUP BY date(created_at). Rồi — và đây là chi tiết khiến biểu đồ vững chãi — một vòng lặp JavaScript nhỏ đi qua bảy ngày lịch gần nhất và điền ngược mọi ngày mà truy vấn không trả về, đẩy vào một số không. Nhờ vậy biểu đồ được đảm bảo luôn đúng bảy điểm.
Chính lời đảm bảo đó khiến các ca biên biến mất thay vì cần rải chốt chặn khắp view. Một tuần rỗng ư? Bảy số không, và một Math.max(count, 1) ở mẫu số giữ đường nằm phẳng ở đáy thay vì chia cho không. Một điểm dữ liệu đơn lẻ có thể khiến công thức khoảng cách trục x i / (n − 1) cho ra NaN ư? Không thể xảy ra — repository không bao giờ phát ra ít hơn bảy. Ngay cả các nhãn ngày trong tuần cũng parse mỗi bucket tại T12:00:00 chứ không phải nửa đêm trần trụi, để một chuỗi YYYY-MM-DD không trượt về ngày hôm trước ở một múi giờ UTC âm. Sửa hình dạng dữ liệu ngay tại nguồn, và mã render được phép ngây thơ một cách có chủ đích.
Tất cả đều ở lại trên máy. Truy vấn thống kê đọc cơ sở dữ liệu cục bộ, trả về qua một kênh IPC có kiểu transcript:get-stats, và chạy hoạt ảnh thành bốn con số đếm-lên khi mount. Không có gì về lịch sử họp hành của bạn rời khỏi chiếc laptop để vẽ biểu đồ này — mà đối với một công cụ ghi lại các cuộc trò chuyện của bạn, đó là cách duy nhất chấp nhận được để dựng một khung phân tích.
Thêm một con bug nữa, vì thiết kế lại lôi chúng ra ánh sáng
Đóng gói cùng bản phát hành là một bản sửa chẳng liên quan gì tới dashboard mà lại liên quan tất tần tật tới loại nợ mà một cuộc thiết kế lại vấp phải. Kiểu dáng scrollbar tối của ứng dụng đã trôi dạt thành hai định nghĩa CSS đối chọi nhau của cùng một class — một cái tím cũ và một cái trắng-trên-nền-tối mới hơn — và cái nào thắng thì tùy thứ tự cascade. Tệ hơn, chỉ những element nào nhớ thêm cái class mới được style; mọi thứ còn lại rơi về scrollbar sáng mặc định, và scrollbar ngang thì chưa bao giờ được style vì các quy tắc cũ chỉ đặt chiều rộng, không bao giờ đặt chiều cao. Bản sửa xóa cả hai định nghĩa, style scrollbar một cách toàn cục trên mọi element, và gỡ cái class nay đã chết khỏi mười component từng mang nó. Đó là một diff hai dòng lặp lại mười lần — thứ thuế chẳng hào nhoáng gì cho việc đã style cùng một thứ hai lần và để cả hai sống sót.
Ba điều bản phát hành này dạy chúng tôi
- Trừ đi để tập trung. Dashboard tốt hơn nhờ làm ít đi — bỏ đi những nút điều khiển ghi âm nó chưa bao giờ cần và trở thành một thứ rõ ràng. Một màn hình vừa là trình xem vừa là điều khiển từ xa là hai nửa-sản-phẩm; hãy chọn một và dời cái kia về đúng chỗ của nó.
- Chọn cách mã hóa mà dữ liệu của bạn xứng đáng. Cùng những con số, các đếm thưa đọc thành sự vắng mặt trong biểu đồ cột và thành một xu hướng trong area chart. Đó không phải tô vẽ — đó là chọn cái hình dạng trung thực để dữ liệu thật, mỏng manh được cất tiếng.
- Đảm bảo hình dạng dữ liệu từ thượng nguồn. Cái vòng lặp điền-ngược-tới-bảy chính là lý do mã biểu đồ không có những kiểm tra null rải rác: chia-cho-không, NaN-một-điểm, và các ngày thiếu đều biến mất vì truy vấn hứa đúng bảy bucket. Render vững chãi bắt đầu từ tầng bên dưới.
Về chương trước trong câu chuyện v1, xem bốn bản phát hành trong 26 tiếng (v1.7.6–v1.8.1); và cho toàn bộ vòng cung, xem giải phẫu việc xuất xưởng phần mềm đến độ hoàn hảo.