This commit is contained in:
2026-01-26 09:05:48 +08:00
commit f218a21377
20 changed files with 7774 additions and 0 deletions

138
ui/components/sidebar.slint Normal file
View File

@@ -0,0 +1,138 @@
// Sidebar Component
// Collapsible navigation sidebar with menu items
import { Theme, Typography, SpacingSystem } from "../theme/theme.slint";
import { Animations } from "../utils/animations.slint";
// Navigation item structure
export struct NavItem {
icon: string, // Text icon/emoji
label: string,
active: bool,
}
export component Sidebar {
// Public properties
in-out property <bool> collapsed: false;
in property <[NavItem]> items: [];
// Callbacks
callback item-clicked(int); // Pass item index
callback toggle-collapsed();
// Calculate width based on collapsed state
private property <length> sidebar-width: collapsed ? 60px : 240px;
width: sidebar-width;
animate width {
duration: Animations.durations.normal;
easing: Animations.ease-in-out;
}
// Main container
Rectangle {
background: Theme.colors.card;
Rectangle {
x: parent.width - 1px;
width: 1px;
height: parent.height;
background: Theme.colors.border;
}
VerticalLayout {
padding: SpacingSystem.spacing.s4;
spacing: SpacingSystem.spacing.s2;
// Toggle button
Rectangle {
height: 40px;
background: Colors.transparent;
border-radius: SpacingSystem.radius.md;
HorizontalLayout {
padding: SpacingSystem.spacing.s2;
spacing: SpacingSystem.spacing.s2;
Text {
text: collapsed ? "☰" : "✕";
font-size: Typography.sizes.xl;
color: Theme.colors.foreground;
horizontal-alignment: center;
vertical-alignment: center;
}
if !collapsed: Text {
text: "Menu";
font-size: Typography.sizes.base;
font-weight: Typography.weights.medium;
color: Theme.colors.foreground;
vertical-alignment: center;
}
}
TouchArea {
clicked => {
root.toggle-collapsed();
}
}
}
// Divider
Rectangle {
height: 1px;
background: Theme.colors.border;
}
// Navigation items
for item[index] in items: Rectangle {
height: 44px;
background: item.active ? Theme.colors.accent : Colors.transparent;
border-radius: SpacingSystem.radius.md;
states [
hovered when touch-area.has-hover && !item.active: {
background: Theme.colors.muted;
}
]
animate background {
duration: Animations.durations.fast;
easing: Animations.ease-in-out;
}
HorizontalLayout {
padding: SpacingSystem.spacing.s2;
spacing: SpacingSystem.spacing.s3;
alignment: start;
// Icon
Text {
text: item.icon;
font-size: Typography.sizes.xl;
color: item.active ? Theme.colors.accent-foreground : Theme.colors.foreground;
horizontal-alignment: center;
vertical-alignment: center;
width: 24px;
}
// Label (only when not collapsed)
if !collapsed: Text {
text: item.label;
font-size: Typography.sizes.base;
font-weight: item.active ? Typography.weights.medium : Typography.weights.normal;
color: item.active ? Theme.colors.accent-foreground : Theme.colors.foreground;
vertical-alignment: center;
}
}
touch-area := TouchArea {
clicked => {
root.item-clicked(index);
}
}
}
}
}
}