diff --git a/.config/quickshell/modules/sidebarLeft/AiChat.qml b/.config/quickshell/modules/sidebarLeft/AiChat.qml index a20bbb23c..a17954e6a 100644 --- a/.config/quickshell/modules/sidebarLeft/AiChat.qml +++ b/.config/quickshell/modules/sidebarLeft/AiChat.qml @@ -16,7 +16,6 @@ import Quickshell.Hyprland Item { id: root - property var panelWindow property var inputField: messageInputField property string commandPrefix: "/" diff --git a/.config/quickshell/modules/sidebarLeft/Anime.qml b/.config/quickshell/modules/sidebarLeft/Anime.qml index 1bfb210ce..8d6c77a3f 100644 --- a/.config/quickshell/modules/sidebarLeft/Anime.qml +++ b/.config/quickshell/modules/sidebarLeft/Anime.qml @@ -17,7 +17,6 @@ import Quickshell.Hyprland Item { id: root - property var panelWindow property var inputField: tagInputField readonly property var responses: Booru.responses property string previewDownloadPath: Directories.booruPreviews diff --git a/.config/quickshell/modules/sidebarLeft/SidebarLeft.qml b/.config/quickshell/modules/sidebarLeft/SidebarLeft.qml index 57c7e6ffe..a6b6c2062 100644 --- a/.config/quickshell/modules/sidebarLeft/SidebarLeft.qml +++ b/.config/quickshell/modules/sidebarLeft/SidebarLeft.qml @@ -17,25 +17,50 @@ Scope { // Scope id: root property int sidebarPadding: 15 property var tabButtonList: [{"icon": "neurology", "name": qsTr("Intelligence")}, {"icon": "bookmark_heart", "name": qsTr("Anime")}] + property int selectedTab: 0 + property bool pin: false + property Component contentComponent: SidebarLeftContent {} + property Item sidebarContent + + Component.onCompleted: { + root.sidebarContent = contentComponent.createObject(null, { + "scopeRoot": root, + }); + sidebarLoader.item.contentParent.children = [root.sidebarContent]; + } + + onPinChanged: { + console.log("Sidebar pin state changed:", root.pin); + if (root.pin) { + sidebarContent.parent = null; // Detach content from sidebar + sidebarLoader.active = false; // Unload sidebar + detachedSidebarLoader.active = true; // Load detached window + detachedSidebarLoader.item.contentParent.children = [sidebarContent]; + } else { + sidebarContent.parent = null; // Detach content from window + detachedSidebarLoader.active = false; // Unload detached window + sidebarLoader.active = true; // Load sidebar + sidebarLoader.item.contentParent.children = [sidebarContent]; + } + } Loader { id: sidebarLoader - active: GlobalStates.sidebarLeftOpen + active: true - PanelWindow { // Window + sourceComponent: PanelWindow { // Window id: sidebarRoot visible: GlobalStates.sidebarLeftOpen - property int selectedTab: 0 property bool extend: false - property bool pin: false property real sidebarWidth: sidebarRoot.extend ? Appearance.sizes.sidebarWidthExtended : Appearance.sizes.sidebarWidth + property var contentParent: sidebarLeftBackground function hide() { GlobalStates.sidebarLeftOpen = false } - exclusiveZone: sidebarRoot.pin ? sidebarWidth : 0 + exclusiveZone: 0 implicitWidth: Appearance.sizes.sidebarWidthExtended + Appearance.sizes.elevationMargin WlrLayershell.namespace: "quickshell:sidebarLeft" // Hyprland 0.49: OnDemand is Exclusive, Exclusive just breaks click-outside-to-close @@ -55,22 +80,22 @@ Scope { // Scope HyprlandFocusGrab { // Click outside to close id: grab windows: [ sidebarRoot ] - active: sidebarRoot.visible && !sidebarRoot.pin + active: sidebarRoot.visible onActiveChanged: { // Focus the selected tab - if (active) swipeView.currentItem.forceActiveFocus() + if (active) sidebarLeftBackground.children[0].focusActiveItem() } onCleared: () => { if (!active) sidebarRoot.hide() } } - // Background + // Content StyledRectangularShadow { target: sidebarLeftBackground + radius: sidebarLeftBackground.radius } Rectangle { id: sidebarLeftBackground - anchors.top: parent.top anchors.left: parent.left anchors.topMargin: Appearance.sizes.hyprlandGapsOut @@ -79,89 +104,48 @@ Scope { // Scope height: parent.height - Appearance.sizes.hyprlandGapsOut * 2 color: Appearance.colors.colLayer0 radius: Appearance.rounding.screenRounding - Appearance.sizes.elevationMargin + 1 - focus: sidebarRoot.visible - - Behavior on width { - animation: Appearance.animation.elementMove.numberAnimation.createObject(this) - } Keys.onPressed: (event) => { - // console.log("Key pressed: " + event.key) if (event.key === Qt.Key_Escape) { sidebarRoot.hide(); } if (event.modifiers === Qt.ControlModifier) { - if (event.key === Qt.Key_PageDown) { - sidebarRoot.selectedTab = Math.min(sidebarRoot.selectedTab + 1, root.tabButtonList.length - 1) - } - else if (event.key === Qt.Key_PageUp) { - sidebarRoot.selectedTab = Math.max(sidebarRoot.selectedTab - 1, 0) - } - else if (event.key === Qt.Key_Tab) { - sidebarRoot.selectedTab = (sidebarRoot.selectedTab + 1) % root.tabButtonList.length; - } - else if (event.key === Qt.Key_Backtab) { - sidebarRoot.selectedTab = (sidebarRoot.selectedTab - 1 + root.tabButtonList.length) % root.tabButtonList.length; - } - else if (event.key === Qt.Key_O) { + if (event.key === Qt.Key_O) { sidebarRoot.extend = !sidebarRoot.extend; } else if (event.key === Qt.Key_P) { - sidebarRoot.pin = !sidebarRoot.pin; + root.pin = !root.pin; } event.accepted = true; } } + } + } + } - ColumnLayout { - anchors.fill: parent - anchors.margins: sidebarPadding - - spacing: sidebarPadding + Loader { + id: detachedSidebarLoader + active: false - PrimaryTabBar { // Tab strip - id: tabBar - tabButtonList: root.tabButtonList - externalTrackedTab: sidebarRoot.selectedTab - function onCurrentIndexChanged(currentIndex) { - sidebarRoot.selectedTab = currentIndex + sourceComponent: FloatingWindow { + id: detachedSidebarRoot + visible: GlobalStates.sidebarLeftOpen + property var contentParent: detachedSidebarBackground + + Rectangle { + id: detachedSidebarBackground + anchors.fill: parent + color: Appearance.colors.colLayer0 + + Keys.onPressed: (event) => { + if (event.modifiers === Qt.ControlModifier) { + if (event.key === Qt.Key_P) { + root.pin = !root.pin; } + event.accepted = true; } - - SwipeView { // Content pages - id: swipeView - Layout.topMargin: 5 - Layout.fillWidth: true - Layout.fillHeight: true - spacing: 10 - - currentIndex: tabBar.externalTrackedTab - onCurrentIndexChanged: { - tabBar.enableIndicatorAnimation = true - sidebarRoot.selectedTab = currentIndex - } - - clip: true - layer.enabled: true - layer.effect: OpacityMask { - maskSource: Rectangle { - width: swipeView.width - height: swipeView.height - radius: Appearance.rounding.small - } - } - - AiChat { - panelWindow: sidebarRoot - } - Anime { - panelWindow: sidebarRoot - } - } - } } - } } diff --git a/.config/quickshell/modules/sidebarLeft/SidebarLeftContent.qml b/.config/quickshell/modules/sidebarLeft/SidebarLeftContent.qml new file mode 100644 index 000000000..6cf7f556f --- /dev/null +++ b/.config/quickshell/modules/sidebarLeft/SidebarLeftContent.qml @@ -0,0 +1,89 @@ +import "root:/" +import "root:/services" +import "root:/modules/common" +import "root:/modules/common/widgets" +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Effects +import Qt5Compat.GraphicalEffects +import Quickshell.Io +import Quickshell +import Quickshell.Widgets +import Quickshell.Wayland +import Quickshell.Hyprland + +Item { + id: sidebarLeftBackground + required property var scopeRoot + anchors.fill: parent + + function focusActiveItem() { + swipeView.currentItem.forceActiveFocus() + } + + Keys.onPressed: (event) => { + if (event.modifiers === Qt.ControlModifier) { + if (event.key === Qt.Key_PageDown) { + scopeRoot.selectedTab = Math.min(scopeRoot.selectedTab + 1, scopeRoot.tabButtonList.length - 1) + event.accepted = true; + } + else if (event.key === Qt.Key_PageUp) { + scopeRoot.selectedTab = Math.max(scopeRoot.selectedTab - 1, 0) + event.accepted = true; + } + else if (event.key === Qt.Key_Tab) { + scopeRoot.selectedTab = (scopeRoot.selectedTab + 1) % scopeRoot.tabButtonList.length; + event.accepted = true; + } + else if (event.key === Qt.Key_Backtab) { + scopeRoot.selectedTab = (scopeRoot.selectedTab - 1 + scopeRoot.tabButtonList.length) % scopeRoot.tabButtonList.length; + event.accepted = true; + } + } + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: sidebarPadding + + spacing: sidebarPadding + + PrimaryTabBar { // Tab strip + id: tabBar + tabButtonList: scopeRoot.tabButtonList + externalTrackedTab: scopeRoot.selectedTab + function onCurrentIndexChanged(currentIndex) { + scopeRoot.selectedTab = currentIndex + } + } + + SwipeView { // Content pages + id: swipeView + Layout.topMargin: 5 + Layout.fillWidth: true + Layout.fillHeight: true + spacing: 10 + + currentIndex: tabBar.externalTrackedTab + onCurrentIndexChanged: { + tabBar.enableIndicatorAnimation = true + scopeRoot.selectedTab = currentIndex + } + + clip: true + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle { + width: swipeView.width + height: swipeView.height + radius: Appearance.rounding.small + } + } + + AiChat {} + Anime {} + } + + } +} \ No newline at end of file