{"body":"#!/usr/bin/env raku\n\nuse Selkie::UI;\n\nsub dark-theme(--> Selkie::Theme) {\n    Theme(\n        base              => Style(:fg(0xEEEEEE), :bg(0x16162E)       ),\n        text              => Style(:fg(0xEEEEEE)                      ),\n        text-dim          => Style(:fg(0x888899)                      ),\n        text-highlight    => Style(:fg(0xFFFFFF), :bold               ),\n        border            => Style(:fg(0x444466)                      ),\n        border-focused    => Style(:fg(0x7AA2F7), :bold               ),\n        input             => Style(:fg(0xEEEEEE), :bg(0x1A1A2E)       ),\n        input-focused     => Style(:fg(0xFFFFFF), :bg(0x2A2A3E)       ),\n        input-placeholder => Style(:fg(0x606080), :italic             ),\n        scrollbar-track   => Style(:fg(0x333344)                      ),\n        scrollbar-thumb   => Style(:fg(0x7AA2F7)                      ),\n        divider           => Style(:fg(0x444466)                      ),\n        tab-active        => Style(:fg(0xFFFFFF), :bg(0x7AA2F7), :bold),\n        tab-inactive      => Style(:fg(0x8888A0), :bg(0x16162E)       ),\n    );\n}\n\nsub light-theme(--> Selkie::Theme) {\n    Theme(\n        base              => Style(:fg(0x222222), :bg(0xF5F5F0)       ),\n        text              => Style(:fg(0x222222)                      ),\n        text-dim          => Style(:fg(0x666666)                      ),\n        text-highlight    => Style(:fg(0x000000), :bold               ),\n        border            => Style(:fg(0xCCCCCC)                      ),\n        border-focused    => Style(:fg(0x3366CC), :bold               ),\n        input             => Style(:fg(0x222222), :bg(0xFFFFFF)       ),\n        input-focused     => Style(:fg(0x000000), :bg(0xEEEEFF)       ),\n        input-placeholder => Style(:fg(0x999999), :italic             ),\n        scrollbar-track   => Style(:fg(0xDDDDDD)                      ),\n        scrollbar-thumb   => Style(:fg(0x3366CC)                      ),\n        divider           => Style(:fg(0xCCCCCC)                      ),\n        tab-active        => Style(:fg(0xFFFFFF), :bg(0x3366CC), :bold),\n        tab-inactive      => Style(:fg(0x666688), :bg(0xF5F5F0)       ),\n    );\n}\n\nselkie-ui Chat {\n    has $.dark     is status<theme>   = True; # You souldn't need to name it, it will use the attr name by default\n    has @.messages is status<messages>;       # You souldn't need to name it, it will use the attr name by default\n\n    method init(%) is handler<app/init> {\n        :db{\n            :messages[\n                {\n                    speaker => 'bot',\n                    text    => 'Hello! Type something and I will echo it back, transformed.'\n                },\n            ],\n        }\n    }\n\n    method chat-send(% (:$text = '', |)) is handler<chat/send> {\n        my $text = $text.trim;\n        if $text.chars {\n            my @messages = @!messages;\n            @messages.push: %( :speaker<you>, :$text );\n            @messages.push: %( :speaker<bot>, :text(\"Reversed: { $text.flip }\") );\n\n            :db{ :@messages }\n        }\n    }\n\n    method chat-clear(%) is handler<chat/clear> { :db { :messages[] } }\n\n    method theme-toggle(%) is handler<chat/clear> { :db { :dark(!$!dark) } }\n\n    method RENDER {\n        App({\n\n            .on-key: 'ctrl+q', -> $ { .quit };\n\n            .on-key: 'ctrl+l', -> $ {\n                .dispatch: 'chat/clear';\n                .toast: 'Cleared';\n            }\n\n            .on-key: 'ctrl+t', -> $ {\n                .dispatch: 'theme/toggle';\n                .toast: 'Theme toggled';\n            };\n\n            VBox({\n\n                Text(\n                    '  Echo Chat  —  Ctrl+Enter send, Ctrl+L clear, Ctrl+T theme, Ctrl+Q quit'\n                ).size(1).style: :fg(0x7AA2F7), :bold;\n\n                Border(\n                    \"Chat\",\n                    CardList.children: {\n                        for @!messages -> %m {\n                            my $is-bot = %m<speaker> eq 'bot';\n                            my %name-style = $is-bot ?? |(:fg(0x9ECE6A), :bold) !! |(:fg(0x7AA2F7), :bold);\n                            my %body-style = |(:fg(0xEEEEEE));\n\n                            Border(\n                                RichText.new(\n                                    Span(\"{%m<speaker>}: \").style(%name-style),\n                                    Span(%m<text>).style: %body-style\n                                );\n                            );\n                        }\n                        .select-last;\n                    }\n                );\n\n                Border(\n                    'Compose',\n                    MultiLineInput('Type a message — Ctrl+Enter to send').max-lines(5).size: 1\n                ).size(3).on-submit.tap: -> $text {\n                    if $text.chars > 0 {\n                        .dispatch('chat/send', :$text);\n                        .clear;\n                    }\n                };\n\n            }).name: \"main\";\n\n            .dispatch: 'app/init';\n        }).theme: { $!dark ?? dark-theme !! light-theme };\n    }\n}\n\n# --- Go -------------------------------------------------------------------\n\nmy $chat = Chat.new;\n$chat.tick;\n\n$chat.focus($input);\n$chat.run;\n","name":"","extension":"raku","url":"https://www.irccloud.com/pastebin/XtCffbni","modified":1776729917,"id":"XtCffbni","size":5197,"lines":136,"own_paste":false,"theme":"","date":1776729917}