// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: MIT import { HorizontalBox, VerticalBox } from "std-widgets.slint"; import { RogPalette } from "../themes/rog_theme.slint"; component SideBarItem inherits Rectangle { // padding only has effect on layout elements // padding: 10px; in property selected; in property has-focus; in-out property text <=> label.text; callback clicked <=> touch.clicked; min-height: self.visible ? l.preferred-height + 10px : 0px; // min-width: self.visible ? l.preferred-width + 10px : 0px; states [ pressed when touch.pressed: { state.opacity: 0.8; } hover when touch.has-hover: { state.opacity: 0.6; } selected when root.selected: { state.opacity: 1; } focused when root.has-focus: { state.opacity: 0.8; } ] state := Rectangle { opacity: 0; border-width: 0px; // Modern look: no full border, maybe just a left bar? // Or keep the ROG style border border-color: RogPalette.accent; background: root.selected ? RogPalette.control-background : RogPalette.alternate-background; // Add a red indicator line on the left for selected items Rectangle { x: 0; width: 4px; height: 100%; background: root.selected ? RogPalette.accent : Colors.transparent; } animate opacity { duration: 150ms; } // animate border-width { duration: 150ms; } height: l.preferred-height; } l := HorizontalBox { y: (parent.height - self.height) / 2; spacing: 0px; label := Text { color: root.selected ? RogPalette.accent : RogPalette.text-primary; vertical-alignment: center; font-size: 14px; font-weight: root.selected ? 700 : 400; } } touch := TouchArea { width: 100%; height: 100%; } } export component SideBar inherits Rectangle { in property <[string]> model: []; in property <[bool]> available: []; in property title <=> label.text; out property current-item: 0; out property current-focused: fs.has-focus ? fs.focused-tab : -1; // The currently focused tab width: 160px; forward-focus: fs; accessible-role: tab; accessible-delegate-focus: root.current-focused >= 0 ? root.current-focused : root.current-item; Rectangle { border-width: 0px; // border-color: RogPalette.accent; border-radius: 0px; background: RogPalette.alternate-background; // Darker sidebar fs := FocusScope { key-pressed(event) => { if (event.text == "\n") { root.current-item = root.current-focused; return accept; } if (event.text == Key.UpArrow) { self.focused-tab = Math.max(self.focused-tab - 1, 0); return accept; } if (event.text == Key.DownArrow) { self.focused-tab = Math.min(self.focused-tab + 1, root.model.length - 1); return accept; } return reject; } key-released(event) => { if (event.text == " ") { root.current-item = root.current-focused; return accept; } return reject; } property focused-tab: 0; x: 0; width: 0; // Do not react on clicks } } VerticalBox { spacing: 4px; alignment: start; label := Text { font-size: 24px; // Larger brand text font-weight: 800; horizontal-alignment: center; color: RogPalette.accent; // ROG Red brand text } // Spacer after brand text Rectangle { height: 20px; } navigation := VerticalLayout { spacing: 4px; // Spacing between items alignment: start; vertical-stretch: 0; for item[index] in root.model: SideBarItem { visible: root.available[index]; clicked => { root.current-item = index; } has-focus: index == root.current-focused; text: item; selected: index == root.current-item; } } VerticalLayout { bottom := VerticalBox { padding-left: 0px; padding-top: 0px; padding-bottom: 0px; @children } } } }