import QtQuick import Quickshell import Quickshell.Wayland import "." as M // Shared flyout popup window — slides down from the bar, dismisses on // click outside. Created on demand via Loader; animates in on creation, // animates out then emits dismissed() for the Loader to deactivate. PanelWindow { id: root default property alias content: contentCol.children required property var screen required property real anchorX property real panelWidth: 220 signal dismissed() visible: true color: "transparent" WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.exclusiveZone: 0 WlrLayershell.namespace: "nova-popup" anchors.top: true anchors.left: true anchors.right: true anchors.bottom: true Component.onCompleted: showAnim.start() function dismiss() { showAnim.stop(); hideAnim.start(); } // Click outside → dismiss MouseArea { anchors.fill: parent onClicked: root.dismiss() } Item { id: panel x: Math.max(0, Math.min( Math.round(root.anchorX - contentCol.width / 2), root.width - contentCol.width )) y: 0 width: contentCol.width height: contentCol.height opacity: 0 // Eat clicks inside the panel MouseArea { anchors.fill: parent } Rectangle { anchors.fill: parent color: M.Theme.base01 opacity: Math.max(M.Theme.barOpacity, 0.85) topLeftRadius: 0 topRightRadius: 0 bottomLeftRadius: M.Theme.radius bottomRightRadius: M.Theme.radius } Column { id: contentCol width: root.panelWidth topPadding: 4 bottomPadding: 4 spacing: 2 } } ParallelAnimation { id: showAnim NumberAnimation { target: panel; property: "opacity"; from: 0; to: 1; duration: 150; easing.type: Easing.OutCubic } NumberAnimation { target: panel; property: "y"; from: -panel.height; to: 0; duration: 200; easing.type: Easing.OutCubic } } ParallelAnimation { id: hideAnim NumberAnimation { target: panel; property: "opacity"; to: 0; duration: 150; easing.type: Easing.InCubic } NumberAnimation { target: panel; property: "y"; to: -panel.height; duration: 150; easing.type: Easing.InCubic } onFinished: root.dismissed() } }