// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie // SPDX-License-Identifier: MIT //! The colors grebe draws with: a palette for light and one for dark, and //! the one in use, which follows what the desktop prefers. const aerie = @import("aerie"); pub const Color = [4]u8; pub const Palette = struct { background: Color, list_background: Color, foreground: Color, dim_foreground: Color, selection_background: Color, selection_foreground: Color, status_background: Color, divider: Color, disabled_foreground: Color, menu_shadow: Color, /// The box around the marked commit. mark: Color, error_foreground: Color, /// The colors lines of descent in the graph are drawn in, one after /// another: distinct from each other and from the selection, and /// strong enough to read against the list. graph: [8]Color, /// The details and diff pane: each kind of line's text, and the band /// behind it, if it has one. diff_added: Color, diff_added_background: Color, diff_removed: Color, diff_removed_background: Color, diff_hunk: Color, diff_hunk_background: Color, diff_file_background: Color, /// The pane's bar of controls, and a control under the pointer. bar_background: Color, control_hover: Color, /// The nodes of the pseudo-commits, as gitk colors them. pseudo_working_tree: Color, pseudo_index: Color, /// Text selected in a field. text_selection: Color, /// Behind a commit the find matched. find_match: Color, /// A scrollbar's track, its thumb, and its thumb while dragged. scrollbar_track: Color, scrollbar_thumb: Color, scrollbar_thumb_active: Color, /// The labels before a subject naming the refs at a commit: behind a /// local branch, a remote one, a tag, and anything else; and their /// border and text. ref_head: Color, ref_remote: Color, ref_tag: Color, ref_other: Color, ref_border: Color, ref_foreground: Color, }; pub const light: Palette = .{ .background = .{ 0xf6, 0xf5, 0xf3, 255 }, .list_background = .{ 0xff, 0xff, 0xff, 255 }, .foreground = .{ 0x1f, 0x23, 0x28, 255 }, .dim_foreground = .{ 0x59, 0x63, 0x6e, 255 }, .selection_background = .{ 0x2f, 0x6f, 0xb3, 255 }, .selection_foreground = .{ 0xff, 0xff, 0xff, 255 }, .status_background = .{ 0xea, 0xe8, 0xe4, 255 }, .divider = .{ 0xd0, 0xcc, 0xc4, 255 }, .disabled_foreground = .{ 0xa8, 0xa8, 0xa8, 255 }, .menu_shadow = .{ 0, 0, 0, 40 }, .mark = .{ 0x1f, 0x23, 0x28, 255 }, .error_foreground = .{ 0xb3, 0x26, 0x1e, 255 }, .graph = .{ .{ 0x2f, 0x6f, 0xb3, 255 }, .{ 0xc0, 0x39, 0x2b, 255 }, .{ 0x27, 0x8e, 0x50, 255 }, .{ 0x8e, 0x44, 0xad, 255 }, .{ 0xd3, 0x7a, 0x00, 255 }, .{ 0x16, 0x8f, 0x8f, 255 }, .{ 0xb0, 0x3a, 0x7a, 255 }, .{ 0x6d, 0x6a, 0x22, 255 }, }, .diff_added = .{ 0x11, 0x63, 0x29, 255 }, .diff_added_background = .{ 0xe6, 0xff, 0xec, 255 }, .diff_removed = .{ 0xa4, 0x0e, 0x26, 255 }, .diff_removed_background = .{ 0xff, 0xeb, 0xe9, 255 }, .diff_hunk = .{ 0x05, 0x50, 0xae, 255 }, .diff_hunk_background = .{ 0xdd, 0xf4, 0xff, 255 }, .diff_file_background = .{ 0xea, 0xee, 0xf2, 255 }, .bar_background = .{ 0xf0, 0xee, 0xea, 255 }, .control_hover = .{ 0xdc, 0xd8, 0xd0, 255 }, .pseudo_working_tree = .{ 0xd0, 0x30, 0x30, 255 }, .pseudo_index = .{ 0x2a, 0x9d, 0x3a, 255 }, .text_selection = .{ 0xc8, 0xdc, 0xf4, 255 }, .find_match = .{ 0xff, 0xe8, 0x82, 255 }, .scrollbar_track = .{ 0xf0, 0xee, 0xea, 255 }, .scrollbar_thumb = .{ 0xbd, 0xb8, 0xae, 255 }, .scrollbar_thumb_active = .{ 0x8f, 0x89, 0x7f, 255 }, .ref_head = .{ 0xc4, 0xf0, 0xc2, 255 }, .ref_remote = .{ 0xff, 0xdd, 0xaa, 255 }, .ref_tag = .{ 0xff, 0xea, 0x2e, 255 }, .ref_other = .{ 0xe2, 0xe0, 0xec, 255 }, .ref_border = .{ 0x59, 0x63, 0x6e, 255 }, .ref_foreground = .{ 0x1f, 0x23, 0x28, 255 }, }; pub const dark: Palette = .{ .background = .{ 0x1c, 0x1e, 0x21, 255 }, .list_background = .{ 0x24, 0x27, 0x2b, 255 }, .foreground = .{ 0xe1, 0xe4, 0xe8, 255 }, .dim_foreground = .{ 0x9a, 0xa3, 0xad, 255 }, .selection_background = .{ 0x2f, 0x6f, 0xb3, 255 }, .selection_foreground = .{ 0xff, 0xff, 0xff, 255 }, .status_background = .{ 0x2a, 0x2d, 0x31, 255 }, .divider = .{ 0x3d, 0x42, 0x48, 255 }, .disabled_foreground = .{ 0x6a, 0x70, 0x77, 255 }, .menu_shadow = .{ 0, 0, 0, 90 }, .mark = .{ 0xe1, 0xe4, 0xe8, 255 }, .error_foreground = .{ 0xff, 0x7b, 0x72, 255 }, .graph = .{ .{ 0x58, 0xa6, 0xff, 255 }, .{ 0xff, 0x7b, 0x72, 255 }, .{ 0x3f, 0xb9, 0x50, 255 }, .{ 0xbc, 0x8c, 0xff, 255 }, .{ 0xf0, 0xa0, 0x30, 255 }, .{ 0x39, 0xc5, 0xcf, 255 }, .{ 0xf7, 0x78, 0xba, 255 }, .{ 0xc9, 0xc2, 0x4a, 255 }, }, .diff_added = .{ 0x7e, 0xe7, 0x87, 255 }, .diff_added_background = .{ 0x1b, 0x3a, 0x26, 255 }, .diff_removed = .{ 0xff, 0xa1, 0x98, 255 }, .diff_removed_background = .{ 0x48, 0x22, 0x23, 255 }, .diff_hunk = .{ 0x79, 0xc0, 0xff, 255 }, .diff_hunk_background = .{ 0x1d, 0x30, 0x46, 255 }, .diff_file_background = .{ 0x30, 0x35, 0x3b, 255 }, .bar_background = .{ 0x2a, 0x2d, 0x31, 255 }, .control_hover = .{ 0x3d, 0x42, 0x48, 255 }, .pseudo_working_tree = .{ 0xf0, 0x50, 0x50, 255 }, .pseudo_index = .{ 0x40, 0xc0, 0x50, 255 }, .text_selection = .{ 0x26, 0x4f, 0x78, 255 }, .find_match = .{ 0x6b, 0x5a, 0x12, 255 }, .scrollbar_track = .{ 0x2a, 0x2d, 0x31, 255 }, .scrollbar_thumb = .{ 0x4f, 0x55, 0x5c, 255 }, .scrollbar_thumb_active = .{ 0x76, 0x7e, 0x88, 255 }, .ref_head = .{ 0x1f, 0x4d, 0x2a, 255 }, .ref_remote = .{ 0x6e, 0x38, 0x12, 255 }, .ref_tag = .{ 0x66, 0x5c, 0x00, 255 }, .ref_other = .{ 0x3a, 0x3e, 0x4c, 255 }, .ref_border = .{ 0x9a, 0xa3, 0xad, 255 }, .ref_foreground = .{ 0xe1, 0xe4, 0xe8, 255 }, }; /// The palette drawn with now. pub var current: *const Palette = &light; /// The palette for what the desktop prefers: dark when it says so, and /// light when it says that or nothing. pub fn forAppearance(a: aerie.desktop.Appearance) *const Palette { return switch (a.color_scheme) { .dark => &dark, .light, .no_preference => &light, }; } /// `c` as the renderer's clear color. pub fn clear(c: Color) [4]f32 { return .{ @as(f32, @floatFromInt(c[0])) / 255, @as(f32, @floatFromInt(c[1])) / 255, @as(f32, @floatFromInt(c[2])) / 255, @as(f32, @floatFromInt(c[3])) / 255, }; } pub fn graphColor(i: u16) Color { return current.graph[i % current.graph.len]; } test "the palette follows the desktop" { const testing = @import("std").testing; try testing.expectEqual(&light, forAppearance(.{})); try testing.expectEqual(&dark, forAppearance(.{ .color_scheme = .dark })); try testing.expectEqual(&light, forAppearance(.{ .color_scheme = .light })); }