slint-ui-system 0.5.0

Neon Design System — Slint UI components for Rust desktop apps. 35+ components, dark/light theme, neon accents.
import { Theme } from "../theme.slint";

export component NeonButton {
    in property <string> text;
    in property <bool> enabled: true;
    in property <bool> has-focus: false;
    callback clicked;

    min-height: 36px;
    min-width: 80px;

    Rectangle {
        background: !root.enabled ? transparent :
                    touch.has-hover ? Theme.neon-cyan : transparent;
        border-radius: Theme.radius-md;
        border-width: 1px;
        border-color: !root.enabled ? Theme.border :
                      root.has-focus ? Theme.border-focus :
                      Theme.neon-cyan;
        opacity: root.enabled ? 1.0 : 0.4;
        HorizontalLayout {
            padding-left: touch.pressed ? 18px : Theme.sp-4;
            padding-right: touch.pressed ? 18px : Theme.sp-4;
            padding-top: Theme.sp-2;
            padding-bottom: Theme.sp-2;
            alignment: center;
            Text {
                text: root.text;
                color: !root.enabled ? Theme.text-dim :
                       touch.has-hover ? Theme.text-inverse : Theme.neon-cyan;
                font-size: Theme.font-base;
                font-weight: 600;
            }
        }
    }
    touch := TouchArea {
        clicked => { if (root.enabled) { root.clicked(); } }
        enabled: root.enabled;
        mouse-cursor: root.enabled ? MouseCursor.pointer : MouseCursor.default;
    }
}

export component PrimaryNeonButton {
    in property <string> text;
    in property <bool> enabled: true;
    in property <bool> has-focus: false;
    callback clicked;
    min-height: 36px; min-width: 80px;
    Rectangle {
        background: !root.enabled ? Theme.bg-surface :
                    touch.has-hover ? Theme.bg-primary-hover : Theme.neon-cyan;
        border-radius: Theme.radius-md;
        border-width: 1px;
        border-color: root.has-focus ? Theme.border-focus :
                      !root.enabled ? Theme.border : Theme.neon-cyan;
        opacity: root.enabled ? 1.0 : 0.4;
        HorizontalLayout {
            padding-left: Theme.sp-4;
            padding-right: Theme.sp-4;
            padding-top: Theme.sp-2;
            padding-bottom: Theme.sp-2;
            alignment: center;
            Text { text: root.text; color: Theme.text-inverse; font-size: Theme.font-base; font-weight: 700; }
        }
    }
    touch := TouchArea {
        clicked => { if (root.enabled) { root.clicked(); } }
        enabled: root.enabled;
        mouse-cursor: root.enabled ? MouseCursor.pointer : MouseCursor.default;
    }
}

export component GhostNeonButton {
    in property <string> text;
    in property <bool> enabled: true;
    in property <bool> has-focus: false;
    callback clicked;
    min-height: 36px; min-width: 80px;
    Rectangle {
        background: !root.enabled ? transparent :
                    touch.has-hover ? Theme.glow-cyan : transparent;
        border-radius: Theme.radius-md;
        border-width: 1px;
        border-color: !root.enabled ? transparent :
                      root.has-focus ? Theme.border-focus : transparent;
        opacity: root.enabled ? 1.0 : 0.4;
        HorizontalLayout {
            padding-left: Theme.sp-4;
            padding-right: Theme.sp-4;
            padding-top: Theme.sp-2;
            padding-bottom: Theme.sp-2;
            alignment: center;
            Text { text: root.text; color: !root.enabled ? Theme.text-dim : Theme.neon-cyan; font-size: Theme.font-base; }
        }
    }
    touch := TouchArea {
        clicked => { if (root.enabled) { root.clicked(); } }
        enabled: root.enabled;
        mouse-cursor: root.enabled ? MouseCursor.pointer : MouseCursor.default;
    }
}

export component DangerNeonButton {
    in property <string> text;
    in property <bool> enabled: true;
    in property <bool> has-focus: false;
    callback clicked;
    min-height: 36px; min-width: 80px;
    Rectangle {
        background: !root.enabled ? transparent :
                    touch.has-hover ? Theme.neon-red : transparent;
        border-radius: Theme.radius-md;
        border-width: 1px;
        border-color: !root.enabled ? Theme.border :
                      root.has-focus ? Theme.border-focus :
                      Theme.neon-red;
        opacity: root.enabled ? 1.0 : 0.4;
        HorizontalLayout {
            padding-left: Theme.sp-4;
            padding-right: Theme.sp-4;
            padding-top: Theme.sp-2;
            padding-bottom: Theme.sp-2;
            alignment: center;
            Text { text: root.text; color: !root.enabled ? Theme.text-dim :
                   touch.has-hover ? Theme.text-inverse : Theme.neon-red; font-size: Theme.font-base; }
        }
    }
    touch := TouchArea {
        clicked => { if (root.enabled) { root.clicked(); } }
        enabled: root.enabled;
        mouse-cursor: root.enabled ? MouseCursor.pointer : MouseCursor.default;
    }
}

export component IconNeonButton {
    in property <string> text;
    in property <bool> enabled: true;
    in property <bool> has-focus: false;
    callback clicked;
    width: 36px; height: 36px;
    Rectangle {
        background: !root.enabled ? transparent :
                    touch.has-hover ? Theme.neon-cyan : transparent;
        border-radius: Theme.radius-md;
        border-width: 1px;
        border-color: !root.enabled ? Theme.border :
                      root.has-focus ? Theme.border-focus :
                      Theme.neon-cyan;
        opacity: root.enabled ? 1.0 : 0.4;
        Text { text: root.text; color: !root.enabled ? Theme.text-dim :
               touch.has-hover ? Theme.text-inverse : Theme.neon-cyan;
               font-size: Theme.font-lg; horizontal-alignment: center; vertical-alignment: center; }
    }
    touch := TouchArea {
        clicked => { if (root.enabled) { root.clicked(); } }
        enabled: root.enabled;
        mouse-cursor: root.enabled ? MouseCursor.pointer : MouseCursor.default;
    }
}

export component ButtonGroup {
    @children
    HorizontalLayout { spacing: Theme.sp-1; alignment: start; }
}