Rework the interface into a consistent visual system.

Replace the accumulated per-widget decoration with short, documented
scales for type, weight, radius and motion. Fills are flat and elevation
is neutral, so accent colour marks state instead of decorating: the
gradients on buttons, pills, nodes and progress bars are gone, along with
the coloured glow shadows and the triple ring on the current unit.

Drop draw_node_halo() and the gradient aura on the learning path, which
painted the same bloom in the cairo layer.

Give the welcome page the app icon, a single-colour heading and an
unboxed paragraph. Restore keyboard focus rings, which were suppressed
everywhere, and clamp exercise bodies to a readable measure on wide
windows.

Fix two layout bugs found on the way: the statistics metric cards were
unequal because hexpand only shares leftover space, and a fraction of
zero still painted a stub of accent colour because GTK gives the progress
node a minimum width.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
pepaskopec-blip 2026-09-17 14:17:34 +02:00
commit ae56a1c1da
11 changed files with 705 additions and 802 deletions

View file

@ -4,6 +4,27 @@
/* Exercise page shell */
/* ------------------------------------------------------------------ */
/* Exercise text would otherwise run the full width of a maximised window,
* which is tiring to read. Keep the body at a comfortable measure and centre
* it once there is room to spare; below that it still fills the page. */
#define EX_BODY_MAX_WIDTH 880
static void ex_body_clamp(GtkAdjustment *adj, GParamSpec *ps, gpointer data) {
GtkWidget *body = data;
double avail = gtk_adjustment_get_page_size(adj);
(void)ps;
if (avail < 1.0)
return;
if (avail < (double)EX_BODY_MAX_WIDTH) {
gtk_widget_set_halign(body, GTK_ALIGN_FILL);
gtk_widget_set_size_request(body, -1, -1);
} else {
gtk_widget_set_halign(body, GTK_ALIGN_CENTER);
gtk_widget_set_size_request(body, EX_BODY_MAX_WIDTH, -1);
}
}
GtkWidget *ex_page_shell(const char *back_target, const char *title,
const char *subtitle, const char *btn_label,
GtkWidget **body_out, GtkWidget **feedback_out,
@ -33,6 +54,9 @@ GtkWidget *ex_page_shell(const char *back_target, const char *title,
body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14);
gtk_widget_set_vexpand(body, TRUE);
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body);
g_signal_connect(gtk_scrolled_window_get_hadjustment(
GTK_SCROLLED_WINDOW(scroll)),
"notify::page-size", G_CALLBACK(ex_body_clamp), body);
*body_out = body;
bottom = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);