Selkie.git | t/ | 03-theme.rakutest


use Test;
use lib 'lib';

use Selkie::Theme;
use Selkie::Style;

plan 9;

sub minimal-theme() {
    Selkie::Theme.new(
        base              => Selkie::Style.new(fg => 0xFFFFFF, bg => 0x000000),
        border            => Selkie::Style.new(fg => 0x444444),
        border-focused    => Selkie::Style.new(fg => 0x00FF00, bold => True),
        text              => Selkie::Style.new(fg => 0xEEEEEE),
        text-dim          => Selkie::Style.new(fg => 0x888888),
        text-highlight    => Selkie::Style.new(fg => 0xFFFFFF, bold => True),
        input             => Selkie::Style.new(fg => 0xEEEEEE, bg => 0x111111),
        input-focused     => Selkie::Style.new(fg => 0xFFFFFF, bg => 0x222222),
        input-placeholder => Selkie::Style.new(fg => 0x666666, italic => True),
        scrollbar-track   => Selkie::Style.new(fg => 0x333333),
        scrollbar-thumb   => Selkie::Style.new(fg => 0x00FF00),
        divider           => Selkie::Style.new(fg => 0x555555),
        tab-active        => Selkie::Style.new(fg => 0xFFFFFF, bg => 0x00FF00, bold => True),
        tab-inactive      => Selkie::Style.new(fg => 0x888888),
    );
}

subtest "default theme construction" => {
    plan 1;
    my $t = Selkie::Theme.default;
    ok $t.defined, "default theme created";
};

subtest "default theme has all required slots" => {
    plan 14;
    my $t = Selkie::Theme.default;
    ok $t.base.defined, "base defined";
    ok $t.border.defined, "border defined";
    ok $t.border-focused.defined, "border-focused defined";
    ok $t.text.defined, "text defined";
    ok $t.text-dim.defined, "text-dim defined";
    ok $t.text-highlight.defined, "text-highlight defined";
    ok $t.input.defined, "input defined";
    ok $t.input-focused.defined, "input-focused defined";
    ok $t.input-placeholder.defined, "input-placeholder defined";
    ok $t.scrollbar-track.defined, "scrollbar-track defined";
    ok $t.scrollbar-thumb.defined, "scrollbar-thumb defined";
    ok $t.divider.defined, "divider defined";
    ok $t.tab-active.defined, "tab-active defined";
    ok $t.tab-inactive.defined, "tab-inactive defined";
};

subtest "defaulted production UI slots are available" => {
    plan 14;
    my $t = Selkie::Theme.default;
    ok $t.control-focused.defined, "control-focused defined";
    ok $t.selection.defined, "selection defined";
    ok $t.dropdown.defined, "dropdown defined";
    ok $t.dropdown-highlight.defined, "dropdown-highlight defined";
    ok $t.overlay-title.defined, "overlay-title defined";
    ok $t.overlay-key.defined, "overlay-key defined";
    ok $t.modal-backdrop.defined, "modal-backdrop defined";
    ok $t.toast.defined, "toast defined";
    ok $t.password-empty.defined, "password-empty defined";
    ok $t.password-weak.defined, "password-weak defined";
    ok $t.password-fair.defined, "password-fair defined";
    ok $t.password-good.defined, "password-good defined";
    ok $t.password-strong.defined, "password-strong defined";
    ok $t.password-very-strong.defined, "password-very-strong defined";
};

subtest "default theme colors are set" => {
    plan 4;
    my $t = Selkie::Theme.default;
    ok $t.base.fg.defined, "base has fg";
    ok $t.base.bg.defined, "base has bg";
    ok $t.text.fg.defined, "text has fg";
    ok $t.border-focused.fg.defined, "border-focused has fg";
};

subtest "custom slot - missing key returns base" => {
    plan 1;
    my $t = Selkie::Theme.default;
    is $t.slot("nonexistent").fg, $t.base.fg, "missing slot returns base style";
};

subtest "custom slot - set and retrieve" => {
    plan 1;
    my $custom = Selkie::Style.new(fg => 0x123456);
    my $t = Selkie::Theme.default;
    $t.custom<my-slot> = $custom;
    is $t.slot("my-slot").fg, 0x123456, "custom slot retrieved";
};

subtest "slot resolves built-in theme slots before custom fallback" => {
    plan 7;
    my $t = Selkie::Theme.default;
    is $t.slot("overlay-title").fg, $t.overlay-title.fg, "overlay-title resolved";
    is $t.slot("control-focused").bg, $t.control-focused.bg, "control-focused resolved";
    is $t.slot("selection").bg, $t.selection.bg, "selection resolved";
    is $t.slot("dropdown").bg, $t.dropdown.bg, "dropdown resolved";
    is $t.slot("dropdown-highlight").fg, $t.dropdown-highlight.fg, "dropdown-highlight resolved";
    is $t.slot("graph-line").fg, $t.graph-line.fg, "graph-line resolved";
    is $t.slot("password-good").fg, $t.password-good.fg, "password-good resolved";
};

subtest "custom theme without defaulted slots keeps compatible defaults" => {
    plan 12;
    my $t = minimal-theme;
    is $t.dropdown.fg, 0xEEEEEE, "dropdown derives fg from input";
    is $t.dropdown.bg, 0x111111, "dropdown derives bg from input";
    is $t.dropdown-highlight.fg, 0xFFFFFF, "dropdown-highlight derives fg from text-highlight";
    is $t.dropdown-highlight.bg, 0x111111, "dropdown-highlight keeps dropdown bg";
    ok $t.dropdown-highlight.bold, "dropdown-highlight keeps highlight bold";
    is $t.password-empty.fg, 0x888888, "empty band derives from text-dim";
    is $t.password-weak.fg, 0xE06060, "weak band default";
    is $t.password-fair.fg, 0xE0A040, "fair band default";
    is $t.password-good.fg, 0xE0E040, "good band default";
    is $t.password-strong.fg, 0x80E060, "strong band default";
    is $t.password-very-strong.fg, 0x40E080, "very strong band default";
    is $t.slot("password-empty").fg, 0x888888, "password slot lookup works";
};

subtest "default theme border-focused is bold" => {
    plan 1;
    my $t = Selkie::Theme.default;
    ok $t.border-focused.bold, "border-focused is bold";
};