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

@ -95,34 +95,42 @@ gboolean on_window_key_pressed(GtkEventControllerKey *controller,
GtkWidget *build_welcome_page(void) {
GtkWidget *box;
GtkWidget *icon;
GtkWidget *heading;
GtkWidget *card;
GtkWidget *body;
GtkWidget *button;
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 18);
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_halign(box, GTK_ALIGN_CENTER);
gtk_widget_set_valign(box, GTK_ALIGN_CENTER);
gtk_widget_set_margin_top(box, 40);
gtk_widget_set_margin_bottom(box, 40);
icon = gtk_image_new_from_icon_name(ICON_NAME);
gtk_image_set_pixel_size(GTK_IMAGE(icon), 88);
gtk_widget_set_halign(icon, GTK_ALIGN_CENTER);
gtk_widget_set_margin_bottom(icon, 22);
gtk_box_append(GTK_BOX(box), icon);
heading = gtk_label_new(NULL);
welcome_heading = heading;
gtk_widget_set_halign(heading, GTK_ALIGN_CENTER);
gtk_widget_add_css_class(heading, "heading");
gtk_box_append(GTK_BOX(box), heading);
card = gtk_label_new(NULL);
i18n_bind(card, "welcome_body", 0);
gtk_label_set_justify(GTK_LABEL(card), GTK_JUSTIFY_CENTER);
gtk_label_set_wrap(GTK_LABEL(card), TRUE);
gtk_label_set_max_width_chars(GTK_LABEL(card), 48);
gtk_widget_add_css_class(card, "card");
gtk_box_append(GTK_BOX(box), card);
body = gtk_label_new(NULL);
i18n_bind(body, "welcome_body", 0);
gtk_label_set_justify(GTK_LABEL(body), GTK_JUSTIFY_CENTER);
gtk_label_set_wrap(GTK_LABEL(body), TRUE);
gtk_label_set_max_width_chars(GTK_LABEL(body), 46);
gtk_widget_set_margin_top(body, 10);
gtk_widget_add_css_class(body, "welcome-body");
gtk_box_append(GTK_BOX(box), body);
button = gtk_button_new();
i18n_bind(button, "continue", 1);
gtk_widget_set_halign(button, GTK_ALIGN_CENTER);
gtk_widget_set_margin_top(button, 6);
gtk_widget_set_margin_top(button, 28);
gtk_widget_add_css_class(button, "btn-primary");
gtk_box_append(GTK_BOX(box), button);