feat(quickshell): give the prompt its own panel, ESC handling and placement

PolkitPanel replaces BarPanel as the dialog's chrome. Deliberately not a
subclass or a fork: most of BarPanel is density machinery — summary slot,
animated height, state pair, transitions — that a modal never uses, and
inheriting it would tie the dialog's look to a component whose real job is the
rail, so every restyle here would have to be justified against the panels up
there. It keeps the shell's silhouette (cut corners with detached accent caps,
the accent rules, the header strip) and drops the rail's tick decoration.

ESC closes the rail. The bar had no keyboard focus at all, so this adds it,
gated by the shell rather than left to the compositor to arbitrate between two
exclusive surfaces — that resolves by stacking and would invert silently the
day the layers change:

    grabsKeyboard: shell.expanded && !polkit.prompting

so ESC dismisses the prompt while one is open and closes the rail afterwards.
Verified by instrumenting the handoff: expanded -> true, prompt open -> false,
prompt dismissed -> true, collapsed -> false. Note the rail now takes EXCLUSIVE
keyboard focus while expanded, which is the cost of answering a keypress the
user has not aimed at anything.

The dialog sits a third of the way down rather than centred, panel centre on
the third so it grows symmetrically as the message wraps, floored at a margin
so a tall prompt on a short output cannot be pushed off the top.

Also carries the backdrop tuning: dim 0.75 -> 0.65, gridOpacity 0.15 -> 0.10,
crossOpacity 0.45 -> 0.15, now that the scrim is used by the prompt as well as
the rail.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GAq2kKCLazZmrKvkd3akud
This commit is contained in:
2026-09-01 23:38:23 +02:00
co-authored by Claude Opus 5
parent 27b924f5e9
commit b3c3cc38f0
6 changed files with 273 additions and 22 deletions
@@ -185,7 +185,16 @@ Scope {
PolkitPromptContent {
id: content
anchors.centerIn: parent
// A third of the way down rather than centred: a password prompt
// reads better above the middle, and on a tall output dead-centre
// puts it below the natural resting line of the eye.
//
// The panel's own CENTRE lands on the third, so the dialog grows
// symmetrically about that line as the message wraps or a pam_info
// line appears. Floored at the same margin the width leaves, so a
// tall prompt on a short output cannot be pushed off the top.
anchors.horizontalCenter: parent.horizontalCenter
y: Math.max(32, Math.round(parent.height / 3 - height / 2))
width: 520
message: root.flow ? root.flow.message : ""