pragma ComponentBehavior: Bound import QtQuick import QtQuick.Shapes import qs.HyprChrome.Theme // Panel chrome for the login greeter. Same vocabulary as PolkitPanel, mirrored: // cuts on the OTHER diagonal (top-left, bottom-right), registration brackets // instead of detached caps, and a segmented accent spine down the left edge. Item { id: panel property string panelId: "" property string title: "" property string meta: "" property int chamfer: 20 property int padding: 18 property int spineWidth: 3 property int spineSegments: 9 // Sweeps the bottom rule while greetd is working. property bool busy: false readonly property int headerHeight: 32 readonly property int headerPadding: 12 property real bracketGap: 6 property real bracketArm: 14 readonly property real activeChamfer: Math.max(2, Math.min(panel.chamfer, panel.height / 2 - 1)) default property alias content: body.data implicitHeight: Math.round(body.y + body.height + panel.padding) Shape { id: panelShape anchors.fill: parent preferredRendererType: Shape.CurveRenderer ShapePath { fillColor: Theme.surface strokeColor: Theme.hair strokeWidth: 1 startX: panel.activeChamfer; startY: 0 PathLine { x: panelShape.width; y: 0 } PathLine { x: panelShape.width; y: panelShape.height - panel.activeChamfer } PathLine { x: panelShape.width - panel.activeChamfer; y: panelShape.height } PathLine { x: 0; y: panelShape.height } PathLine { x: 0; y: panel.activeChamfer } PathLine { x: panel.activeChamfer; y: 0 } } // Accent along each cut, inset so it reads as an edge highlight. ShapePath { fillColor: "transparent" strokeColor: Theme.accent strokeWidth: 2 capStyle: ShapePath.FlatCap startX: 0; startY: panel.activeChamfer PathLine { x: panel.activeChamfer; y: 0 } } ShapePath { fillColor: "transparent" strokeColor: Theme.accent strokeWidth: 2 capStyle: ShapePath.FlatCap startX: panelShape.width; startY: panelShape.height - panel.activeChamfer PathLine { x: panelShape.width - panel.activeChamfer; y: panelShape.height } } // Registration brackets on the two square corners, echoing the // backdrop's crosses. ShapePath { fillColor: "transparent" strokeColor: Theme.muted strokeWidth: 1 startX: panelShape.width + panel.bracketGap - panel.bracketArm startY: -panel.bracketGap PathLine { x: panelShape.width + panel.bracketGap; y: -panel.bracketGap } PathLine { x: panelShape.width + panel.bracketGap; y: -panel.bracketGap + panel.bracketArm } } ShapePath { fillColor: "transparent" strokeColor: Theme.muted strokeWidth: 1 startX: -panel.bracketGap startY: panelShape.height + panel.bracketGap - panel.bracketArm PathLine { x: -panel.bracketGap; y: panelShape.height + panel.bracketGap } PathLine { x: -panel.bracketGap + panel.bracketArm; y: panelShape.height + panel.bracketGap } } } // Segmented spine, below the header. Column { x: 0 y: panel.headerHeight + 8 spacing: 3 readonly property real segment: (panel.height - panel.headerHeight - 8 - panel.activeChamfer - 8 - (panel.spineSegments - 1) * spacing) / panel.spineSegments Repeater { model: panel.spineSegments Rectangle { required property int index width: panel.spineWidth height: Math.max(1, parent.segment) color: Theme.accent // Fades downward. opacity: 1 - index / panel.spineSegments * 0.85 } } } // Header: title, meta, slug chip on the right. Text { x: panel.activeChamfer + panel.headerPadding anchors.verticalCenter: header.verticalCenter text: panel.title color: Theme.text font.family: Theme.displayFont font.pixelSize: 12 font.bold: true font.letterSpacing: 1.4 } Row { id: header anchors.right: parent.right anchors.rightMargin: panel.headerPadding y: Math.round((panel.headerHeight - height) / 2) spacing: 12 Text { anchors.verticalCenter: slugChip.verticalCenter visible: panel.meta.length > 0 text: panel.meta color: Theme.muted font.family: Theme.microFont font.pixelSize: 8 font.letterSpacing: 0.7 } Rectangle { id: slugChip width: slugText.implicitWidth + 10 height: slugText.implicitHeight + 4 color: "transparent" border.width: 1 border.color: Theme.accent Text { id: slugText anchors.centerIn: parent text: panel.panelId color: Theme.accent font.family: Theme.microFont font.pixelSize: 11 font.bold: true } } } // Header rule: dashed, not solid, to set it apart from the polkit dialog. Row { x: panel.activeChamfer y: panel.headerHeight spacing: 3 Repeater { model: Math.max(0, Math.floor((panel.width - panel.activeChamfer - 1) / 9)) Rectangle { width: 6 height: 1 color: Theme.textAlpha(0.18) } } } // Busy sweep along the bottom edge. Item { x: 0 y: panel.height - 2 width: panel.width - panel.activeChamfer height: 2 clip: true visible: panel.busy Rectangle { id: sweep width: parent.width / 4 height: parent.height color: Theme.accent NumberAnimation on x { running: panel.busy loops: Animation.Infinite from: -sweep.width to: panel.width duration: 900 easing.type: Easing.InOutQuad } } } Item { id: body x: panel.padding + panel.spineWidth y: panel.headerHeight + panel.padding width: Math.max(0, panel.width - panel.padding * 2 - panel.spineWidth) height: childrenRect.height } }