summaryrefslogtreecommitdiff
path: root/modules/controlcenter/NavRail.qml
diff options
context:
space:
mode:
Diffstat (limited to 'modules/controlcenter/NavRail.qml')
-rw-r--r--modules/controlcenter/NavRail.qml203
1 files changed, 203 insertions, 0 deletions
diff --git a/modules/controlcenter/NavRail.qml b/modules/controlcenter/NavRail.qml
new file mode 100644
index 0000000..a631465
--- /dev/null
+++ b/modules/controlcenter/NavRail.qml
@@ -0,0 +1,203 @@
+pragma ComponentBehavior: Bound
+
+import qs.components
+import qs.services
+import qs.config
+import QtQuick
+import QtQuick.Layouts
+
+Item {
+ id: root
+
+ required property Session session
+ property bool expanded
+
+ implicitWidth: layout.implicitWidth + Appearance.padding.large * 4
+ implicitHeight: layout.implicitHeight + Appearance.padding.large * 2
+
+ ColumnLayout {
+ id: layout
+
+ anchors.centerIn: parent
+ spacing: Appearance.spacing.normal
+
+ states: State {
+ name: "expanded"
+ when: root.expanded
+
+ PropertyChanges {
+ layout.spacing: Appearance.spacing.small
+ menuIcon.opacity: 0
+ menuIconExpanded.opacity: 1
+ menuIcon.rotation: 180
+ menuIconExpanded.rotation: 0
+ }
+ AnchorChanges {
+ target: menuIcon
+ anchors.horizontalCenter: undefined
+ }
+ AnchorChanges {
+ target: menuIconExpanded
+ anchors.horizontalCenter: undefined
+ }
+ }
+
+ transitions: Transition {
+ Anim {
+ properties: "spacing,opacity,rotation"
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.bottomMargin: Appearance.spacing.large * 2
+ implicitHeight: Math.max(menuIcon.implicitHeight, menuIconExpanded.implicitHeight) + Appearance.padding.normal * 2
+
+ StateLayer {
+ radius: Appearance.rounding.small
+
+ function onClicked(): void {
+ root.expanded = !root.expanded;
+ }
+ }
+
+ MaterialIcon {
+ id: menuIcon
+
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ text: "menu"
+ font.pointSize: Appearance.font.size.large
+ }
+
+ MaterialIcon {
+ id: menuIconExpanded
+
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ text: "menu_open"
+ font.pointSize: Appearance.font.size.large
+ opacity: 0
+ rotation: -180
+ }
+ }
+
+ NavItem {
+ icon: "network_manage"
+ label: "network"
+ }
+
+ NavItem {
+ icon: "settings_bluetooth"
+ label: "bluetooth"
+ }
+
+ NavItem {
+ icon: "tune"
+ label: "audio"
+ }
+ }
+
+ component NavItem: Item {
+ id: item
+
+ required property string icon
+ required property string label
+ readonly property bool active: root.session.active === label
+
+ implicitWidth: background.implicitWidth
+ implicitHeight: background.implicitHeight + smallLabel.implicitHeight + smallLabel.anchors.topMargin
+
+ states: State {
+ name: "expanded"
+ when: root.expanded
+
+ PropertyChanges {
+ expandedLabel.opacity: 1
+ smallLabel.opacity: 0
+ background.implicitWidth: Config.controlCenter.sizes.expandedNavWidth
+ background.implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2
+ item.implicitHeight: background.implicitHeight
+ }
+ }
+
+ transitions: Transition {
+ Anim {
+ property: "opacity"
+ duration: Appearance.anim.durations.small
+ }
+
+ Anim {
+ properties: "implicitWidth,implicitHeight"
+ duration: Appearance.anim.durations.expressiveDefaultSpatial
+ easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
+ }
+ }
+
+ StyledRect {
+ id: background
+
+ radius: Appearance.rounding.full
+ color: item.active ? Colours.palette.m3secondaryContainer : Colours.palette.m3surfaceContainer
+
+ implicitWidth: icon.implicitWidth + icon.anchors.leftMargin * 2
+ implicitHeight: icon.implicitHeight + Appearance.padding.small
+
+ StateLayer {
+ color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
+
+ function onClicked(): void {
+ root.session.active = item.label;
+ }
+ }
+
+ MaterialIcon {
+ id: icon
+
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.leftMargin: Appearance.padding.large
+
+ text: item.icon
+ color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
+ font.pointSize: Appearance.font.size.large
+ fill: item.active ? 1 : 0
+
+ Behavior on fill {
+ Anim {}
+ }
+ }
+
+ StyledText {
+ id: expandedLabel
+
+ anchors.left: icon.right
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.leftMargin: Appearance.spacing.normal
+
+ opacity: 0
+ text: item.label
+ color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
+ font.capitalization: Font.Capitalize
+ }
+
+ StyledText {
+ id: smallLabel
+
+ anchors.horizontalCenter: icon.horizontalCenter
+ anchors.top: icon.bottom
+ anchors.topMargin: Appearance.spacing.small / 2
+
+ text: item.label
+ font.pointSize: Appearance.font.size.small
+ font.capitalization: Font.Capitalize
+ }
+ }
+ }
+
+ component Anim: NumberAnimation {
+ duration: Appearance.anim.durations.normal
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Appearance.anim.curves.standard
+ }
+}