diff --git a/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml b/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml index 6f59db49..91f74060 100644 --- a/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml +++ b/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml @@ -216,8 +216,26 @@ Scope { Item { id: spotlightContainer + + // Connected-frame mode: dock flush against the emerge-side frame + // edge and slide in from beyond that edge. In any other mode the + // spotlight stays centered — identical to master. + readonly property string connectedEmergeSide: SettingsData.frameLauncherEmergeSide || "bottom" + readonly property real _centerY: (parent.height - height) / 2 + readonly property real _connectedRestY: { + if (!Theme.isConnectedEffect || !overlayWindow.screen) + return _centerY; + const inset = SettingsData.frameEdgeInsetForSide(overlayWindow.screen, connectedEmergeSide); + return connectedEmergeSide === "top" ? inset : parent.height - height - inset; + } + readonly property real _connectedCollapsedY: connectedEmergeSide === "top" ? -height : parent.height + x: Theme.snap((parent.width - width) / 2, overlayWindow.dpr) - y: Theme.snap((parent.height - height) / 2, overlayWindow.dpr) + y: { + if (!Theme.isConnectedEffect) + return Theme.snap(_centerY, overlayWindow.dpr); + return Theme.snap(overlayWindow.shouldShowSpotlight ? _connectedRestY : _connectedCollapsedY, overlayWindow.dpr); + } readonly property int baseWidth: { switch (SettingsData.dankLauncherV2Size) { @@ -248,8 +266,8 @@ Scope { readonly property bool animatingOut: niriOverviewScope.isClosing && overlayWindow.isSpotlightScreen - scale: overlayWindow.shouldShowSpotlight ? 1.0 : 0.96 - opacity: overlayWindow.shouldShowSpotlight ? 1 : 0 + scale: Theme.isConnectedEffect ? 1.0 : (overlayWindow.shouldShowSpotlight ? 1.0 : 0.96) + opacity: Theme.isConnectedEffect ? 1 : (overlayWindow.shouldShowSpotlight ? 1 : 0) visible: overlayWindow.shouldShowSpotlight || animatingOut enabled: overlayWindow.shouldShowSpotlight @@ -259,6 +277,7 @@ Scope { Behavior on scale { id: scaleAnimation + enabled: !Theme.isConnectedEffect NumberAnimation { duration: Theme.expressiveDurations.fast easing.type: Easing.BezierSpline @@ -272,6 +291,7 @@ Scope { } Behavior on opacity { + enabled: !Theme.isConnectedEffect NumberAnimation { duration: Theme.expressiveDurations.fast easing.type: Easing.BezierSpline @@ -279,6 +299,23 @@ Scope { } } + // Connected-mode slide — only animates in full connected-frame mode. + // Drives resetState when the slide-out finishes (scale/opacity are + // static in connected mode so their onRunningChanged never fires). + Behavior on y { + enabled: Theme.isConnectedEffect + NumberAnimation { + duration: Theme.variantDuration(Theme.popoutAnimationDuration, overlayWindow.shouldShowSpotlight) + easing.type: Easing.BezierSpline + easing.bezierCurve: overlayWindow.shouldShowSpotlight ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve + onRunningChanged: { + if (running || !spotlightContainer.animatingOut) + return; + niriOverviewScope.resetState(); + } + } + } + Rectangle { anchors.fill: parent color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)