From 9f4c75a75cf08175d34d6cd78b25b1ee8a89f248 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 18 Jun 2025 23:56:47 +0200 Subject: [PATCH] settings: pages --- .../common/widgets/NavigationRailButton.qml | 36 ++- .config/quickshell/modules/settings/About.qml | 13 ++ .../quickshell/modules/settings/General.qml | 13 ++ .../quickshell/modules/settings/Services.qml | 13 ++ .config/quickshell/modules/settings/Style.qml | 13 ++ .config/quickshell/settings.qml | 205 +++++++++++++----- 6 files changed, 225 insertions(+), 68 deletions(-) create mode 100644 .config/quickshell/modules/settings/About.qml create mode 100644 .config/quickshell/modules/settings/General.qml create mode 100644 .config/quickshell/modules/settings/Services.qml create mode 100644 .config/quickshell/modules/settings/Style.qml diff --git a/.config/quickshell/modules/common/widgets/NavigationRailButton.qml b/.config/quickshell/modules/common/widgets/NavigationRailButton.qml index 500744949..615cb35eb 100644 --- a/.config/quickshell/modules/common/widgets/NavigationRailButton.qml +++ b/.config/quickshell/modules/common/widgets/NavigationRailButton.qml @@ -13,13 +13,19 @@ TabButton { property string buttonIcon property string buttonText property bool expanded: false + property bool showToggledHighlight: true + readonly property real visualWidth: root.expanded ? root.baseSize + 20 + itemText.implicitWidth : root.baseSize property real baseSize: 56 property real baseHighlightHeight: 32 + property real highlightCollapsedTopMargin: 8 padding: 0 + // The navigation item’s target area always spans the full width of the + // nav rail, even if the item container hugs its contents. + Layout.fillWidth: true + // implicitWidth: contentItem.implicitWidth implicitHeight: baseSize - implicitWidth: contentItem.implicitWidth background: null PointingHandInteraction {} @@ -28,23 +34,26 @@ TabButton { contentItem: Item { id: buttonContent anchors { + top: parent.top + bottom: parent.bottom left: parent.left - verticalCenter: parent.verticalCenter + right: undefined } - implicitWidth: root.expanded ? itemIconBackground.implicitWidth + 20 + itemText.implicitWidth : - itemIconBackground.implicitWidth + implicitWidth: root.visualWidth implicitHeight: root.expanded ? itemIconBackground.implicitHeight : itemIconBackground.implicitHeight + itemText.implicitHeight Rectangle { id: itemBackground anchors.top: itemIconBackground.top anchors.left: itemIconBackground.left - anchors.right: itemIconBackground.right anchors.bottom: itemIconBackground.bottom + implicitWidth: root.visualWidth radius: Appearance.rounding.full color: toggled ? - (root.down ? Appearance.colors.colSecondaryContainerActive : root.hovered ? Appearance.colors.colSecondaryContainerHover : Appearance.colors.colSecondaryContainer) : + root.showToggledHighlight ? + (root.down ? Appearance.colors.colSecondaryContainerActive : root.hovered ? Appearance.colors.colSecondaryContainerHover : Appearance.colors.colSecondaryContainer) + : ColorUtils.transparentize(Appearance.colors.colSecondaryContainer) : (root.down ? Appearance.colors.colLayer1Active : root.hovered ? Appearance.colors.colLayer1Hover : ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1)) states: State { @@ -54,9 +63,12 @@ TabButton { target: itemBackground anchors.top: buttonContent.top anchors.left: buttonContent.left - anchors.right: buttonContent.right anchors.bottom: buttonContent.bottom } + PropertyChanges { + target: itemBackground + implicitWidth: root.visualWidth + } } transitions: Transition { AnchorAnimation { @@ -64,6 +76,13 @@ TabButton { easing.type: Appearance.animation.elementMoveFast.type easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve } + PropertyAnimation { + target: itemBackground + property: "implicitWidth" + duration: Appearance.animation.elementMove.duration + easing.type: Appearance.animation.elementMove.type + easing.bezierCurve: Appearance.animation.elementMove.bezierCurve + } } Behavior on color { @@ -84,6 +103,7 @@ TabButton { anchors.centerIn: parent iconSize: 24 fill: toggled ? 1 : 0 + font.weight: (toggled || root.hovered) ? Font.DemiBold : Font.Normal text: buttonIcon color: toggled ? Appearance.m3colors.m3onSecondaryContainer : Appearance.colors.colOnLayer1 @@ -97,7 +117,7 @@ TabButton { id: itemText anchors { top: itemIconBackground.bottom - topMargin: 6 + topMargin: 2 horizontalCenter: itemIconBackground.horizontalCenter } states: State { diff --git a/.config/quickshell/modules/settings/About.qml b/.config/quickshell/modules/settings/About.qml new file mode 100644 index 000000000..1d35b71b3 --- /dev/null +++ b/.config/quickshell/modules/settings/About.qml @@ -0,0 +1,13 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import "root:/services/" +import "root:/modules/common/" +import "root:/modules/common/widgets/" + +ContentPage { + StyledText { + text: qsTr("About page") + font.pixelSize: Appearance.font.pixelSize.larger + } +} \ No newline at end of file diff --git a/.config/quickshell/modules/settings/General.qml b/.config/quickshell/modules/settings/General.qml new file mode 100644 index 000000000..f998ea00c --- /dev/null +++ b/.config/quickshell/modules/settings/General.qml @@ -0,0 +1,13 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import "root:/services/" +import "root:/modules/common/" +import "root:/modules/common/widgets/" + +ContentPage { + StyledText { + text: qsTr("General page") + font.pixelSize: Appearance.font.pixelSize.larger + } +} \ No newline at end of file diff --git a/.config/quickshell/modules/settings/Services.qml b/.config/quickshell/modules/settings/Services.qml new file mode 100644 index 000000000..d7d8184f1 --- /dev/null +++ b/.config/quickshell/modules/settings/Services.qml @@ -0,0 +1,13 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import "root:/services/" +import "root:/modules/common/" +import "root:/modules/common/widgets/" + +ContentPage { + StyledText { + text: qsTr("Services page") + font.pixelSize: Appearance.font.pixelSize.larger + } +} \ No newline at end of file diff --git a/.config/quickshell/modules/settings/Style.qml b/.config/quickshell/modules/settings/Style.qml new file mode 100644 index 000000000..6b60c1224 --- /dev/null +++ b/.config/quickshell/modules/settings/Style.qml @@ -0,0 +1,13 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import "root:/services/" +import "root:/modules/common/" +import "root:/modules/common/widgets/" + +ContentPage { + StyledText { + text: qsTr("Style settings page") + font.pixelSize: Appearance.font.pixelSize.larger + } +} \ No newline at end of file diff --git a/.config/quickshell/settings.qml b/.config/quickshell/settings.qml index fd3193440..58d853f32 100644 --- a/.config/quickshell/settings.qml +++ b/.config/quickshell/settings.qml @@ -26,7 +26,30 @@ ApplicationWindow { property string firstRunFileContent: "This file is just here to confirm you've been greeted :>" property real contentPadding: 8 property bool showNextTime: false + property var pages: [ + { + name: "General", + icon: "tune", + component: "modules/settings/General.qml" + }, + { + name: "Style", + icon: "palette", + component: "modules/settings/Style.qml" + }, + { + name: "Services", + icon: "settings", + component: "modules/settings/Services.qml" + }, + { + name: "About", + icon: "info", + component: "modules/settings/About.qml" + } + ] property int currentPage: 0 + visible: true onClosing: Qt.quit() title: "illogical-impulse Settings" @@ -42,23 +65,6 @@ ApplicationWindow { height: 650 color: Appearance.m3colors.m3background - component Section: ColumnLayout { - id: sectionRoot - property string title - default property alias data: sectionContent.data - - Layout.fillWidth: true - spacing: 8 - StyledText { - text: sectionRoot.title - font.pixelSize: Appearance.font.pixelSize.larger - } - ColumnLayout { - id: sectionContent - spacing: 5 - } - } - ColumnLayout { anchors { fill: parent @@ -101,54 +107,90 @@ ApplicationWindow { Layout.fillWidth: true Layout.fillHeight: true spacing: contentPadding - NavigationRail { // Window content with navigation rail and content pane - id: navRail + Item { + id: navRailWrapper Layout.fillHeight: true Layout.margins: 5 - spacing: 10 - expanded: root.width > 900 - - NavigationRailExpandButton {} - - FloatingActionButton { - id: fab - iconText: "edit" - buttonText: "Edit config" - expanded: navRail.expanded - onClicked: { - Qt.openUrlExternally(`${Directories.config}/illogical-impulse/config.json`); - } + implicitWidth: navRail.expanded ? 150 : fab.baseSize + Behavior on implicitWidth { + animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } - - ColumnLayout { - Layout.topMargin: 25 - spacing: 4 - - NavigationRailButton { - toggled: root.currentPage === 0 - onClicked: root.currentPage = 0; - expanded: navRail.expanded - buttonIcon: "tune" - buttonText: "General" + NavigationRail { // Window content with navigation rail and content pane + id: navRail + anchors { + left: parent.left + top: parent.top + bottom: parent.bottom } - NavigationRailButton { - toggled: root.currentPage === 1 - onClicked: root.currentPage = 1; - expanded: navRail.expanded - buttonIcon: "dashboard" - buttonText: "Widgets" - } - NavigationRailButton { - toggled: root.currentPage === 2 - onClicked: root.currentPage = 2; - expanded: navRail.expanded - buttonIcon: "settings" - buttonText: "Services" - } - } + spacing: 10 + expanded: root.width > 900 + + NavigationRailExpandButton {} - Item { - Layout.fillHeight: true + FloatingActionButton { + id: fab + iconText: "edit" + buttonText: "Edit config" + expanded: navRail.expanded + onClicked: { + Qt.openUrlExternally(`${Directories.config}/illogical-impulse/config.json`); + } + + StyledToolTip { + extraVisibleCondition: !navRail.expanded + content: "Edit shell config file" + } + } + + Item { + implicitHeight: tabBarColumn.implicitHeight + implicitWidth: tabBarColumn.implicitWidth + Layout.topMargin: 25 + Rectangle { + property real itemHeight: tabBarColumn.children[0].baseSize + property real baseHighlightHeight: tabBarColumn.children[0].baseHighlightHeight + anchors { + top: tabBarColumn.top + left: tabBarColumn.left + topMargin: itemHeight * root.currentPage + (navRail.expanded ? 0 : ((itemHeight - baseHighlightHeight) / 2)) + } + radius: Appearance.rounding.full + color: Appearance.colors.colSecondaryContainer + implicitHeight: navRail.expanded ? itemHeight : baseHighlightHeight + implicitWidth: tabBarColumn.children[root.currentPage].visualWidth + + Behavior on anchors.topMargin { + NumberAnimation { + duration: Appearance.animationCurves.expressiveFastSpatialDuration + easing.type: Appearance.animation.elementMove.type + easing.bezierCurve: Appearance.animationCurves.expressiveFastSpatial + } + } + } + ColumnLayout { + id: tabBarColumn + anchors.fill: parent + spacing: 0 + + Repeater { + model: root.pages + NavigationRailButton { + required property var index + required property var modelData + toggled: root.currentPage === index + onClicked: root.currentPage = index; + expanded: navRail.expanded + buttonIcon: modelData.icon + buttonText: modelData.name + showToggledHighlight: false + } + } + } + } + + Item { + Layout.fillHeight: true + } } } Rectangle { // Content container @@ -156,6 +198,49 @@ ApplicationWindow { Layout.fillHeight: true color: Appearance.m3colors.m3surfaceContainerLow radius: Appearance.rounding.windowRounding - root.contentPadding + + Loader { + id: pageLoader + anchors.fill: parent + opacity: 1.0 + source: root.pages[0].component + Connections { + target: root + function onCurrentPageChanged() { + if (pageLoader.sourceComponent !== root.pages[root.currentPage].component) { + switchAnim.restart(); + } + } + } + + SequentialAnimation { + id: switchAnim + + NumberAnimation { + target: pageLoader + properties: "opacity" + from: 1 + to: 0 + duration: 200 + easing.type: Appearance.animation.elementMoveExit.type + easing.bezierCurve: Appearance.animation.elementMoveExit.bezierCurve + } + PropertyAction { + target: pageLoader + property: "source" + value: root.pages[root.currentPage].component + } + NumberAnimation { + target: pageLoader + properties: "opacity" + from: 0 + to: 1 + duration: 200 + easing.type: Appearance.animation.elementMoveEnter.type + easing.bezierCurve: Appearance.animation.elementMoveEnter.bezierCurve + } + } + } } } }