Build the Panama Hyprland desktop

This commit is contained in:
Gabriel Brown
2026-08-17 10:32:55 -04:00
parent 67033f2a31
commit 5248883e4b
190 changed files with 18554 additions and 34 deletions
@@ -0,0 +1,134 @@
// Quiet transient Signal Glass content. It acknowledges one meaningful state
// transition and then leaves; it is not a notification and has no history.
import QtQuick
import qs.config
import qs.services
import qs.widgets
Rectangle {
id: root
required property var event
readonly property color toneColor: {
if (event?.tone === "danger")
return Theme.danger;
if (event?.tone === "warn")
return Theme.warn;
if (event?.tone === "ok")
return Theme.ok;
return Theme.accent;
}
radius: Theme.popoverRadius
color: Theme.alpha(Theme.bgPopover, 0.86)
border.width: 1
border.color: Theme.alpha(Theme.fg, 0.09)
PrismEdge {
anchors.top: parent.top
anchors.topMargin: 1
anchors.left: parent.left
anchors.right: parent.right
inset: parent.radius
}
Rectangle {
id: mark
anchors.left: parent.left
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
width: 38
height: 38
radius: 19
border.width: 0
color: Theme.alpha(root.toneColor, 0.14)
Text {
anchors.centerIn: parent
visible: root.event?.glyph !== ""
text: root.event?.glyph ?? ""
color: root.toneColor
font.family: Theme.fontMono
font.pixelSize: 19
}
ThemedIcon {
anchors.centerIn: parent
visible: root.event?.glyph === ""
size: 19
icon: root.event?.icon ?? "dialog-information-symbolic"
tint: root.toneColor
}
}
Column {
anchors.left: mark.right
anchors.leftMargin: 11
anchors.right: closeButton.left
anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter
spacing: 2
Text {
width: parent.width
text: root.event?.title ?? ""
color: Theme.fg
elide: Text.ElideRight
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
font.weight: Font.DemiBold
}
Text {
width: parent.width
visible: text !== ""
text: root.event?.detail ?? ""
color: Theme.fgDim
elide: Text.ElideRight
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
}
}
Rectangle {
id: closeButton
anchors.right: parent.right
anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter
width: 28
height: 28
radius: 14
border.width: 0
color: closeMouse.containsMouse ? Theme.alpha(Theme.fg, Theme.hoverAlpha) : "transparent"
ThemedIcon {
anchors.centerIn: parent
size: 14
icon: "window-close-symbolic"
tint: Theme.fgDim
}
MouseArea {
id: closeMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: StatusEvents.dismiss()
}
}
MouseArea {
anchors.left: parent.left
anchors.right: closeButton.left
anchors.top: parent.top
anchors.bottom: parent.bottom
cursorShape: root.event?.actionId ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (root.event?.actionId)
StatusEvents.invoke();
else
StatusEvents.dismiss();
}
}
}
@@ -0,0 +1,169 @@
// Rich persistent mode of Signal Glass. Dismiss hides controls only; the
// compact bar timer remains until the session ends.
import QtQuick
import qs.config
import qs.modules.focus
import qs.services
import qs.widgets
Rectangle {
id: root
radius: Theme.popoverRadius
color: Theme.alpha(Theme.bgPopover, 0.88)
border.width: 1
border.color: Theme.alpha(Theme.fg, 0.1)
PrismEdge {
anchors.top: parent.top
anchors.topMargin: 1
anchors.left: parent.left
anchors.right: parent.right
inset: parent.radius
}
Item {
id: primary
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 12
height: 54
Rectangle {
id: focusMark
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: 38
height: 38
radius: 19
border.width: 0
color: Theme.alpha(Theme.accent, 0.16)
Text {
anchors.centerIn: parent
text: "\u{F051F}"
color: Theme.accent
font.family: Theme.fontMono
font.pixelSize: 20
}
}
Column {
anchors.left: focusMark.right
anchors.leftMargin: 11
anchors.right: remaining.left
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
spacing: 2
Text {
width: parent.width
text: FocusSession.workspaceLabel || "Focus session"
color: Theme.fg
elide: Text.ElideRight
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.DemiBold
}
Text {
width: parent.width
text: FocusSession.statusText
color: FocusSession.paused ? Theme.warn : Theme.fgDim
elide: Text.ElideRight
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
}
}
Text {
id: remaining
anchors.right: closeButton.left
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter
text: FocusSession.remainingText
color: FocusSession.paused ? Theme.warn : Theme.fg
font.family: Theme.fontFamily
font.features: Theme.tabularFigures
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.DemiBold
}
Rectangle {
id: closeButton
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
width: 28
height: 28
radius: 14
border.width: 0
color: closeMouse.containsMouse ? Theme.alpha(Theme.fg, Theme.hoverAlpha) : "transparent"
ThemedIcon {
anchors.centerIn: parent
size: 14
icon: "window-close-symbolic"
tint: Theme.fgDim
}
MouseArea {
id: closeMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: FocusSession.dismiss()
}
}
MouseArea {
anchors.left: parent.left
anchors.right: closeButton.left
anchors.top: parent.top
anchors.bottom: parent.bottom
cursorShape: Qt.PointingHandCursor
z: -1
onClicked: {
FocusSession.activateWorkspace();
FocusSession.dismiss();
}
}
}
Row {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.leftMargin: 12
anchors.rightMargin: 12
anchors.bottomMargin: 12
spacing: Theme.itemSpacing
FocusAction {
width: (parent.width - parent.spacing * 2) / 3
icon: FocusSession.paused ? "media-playback-start-symbolic" : "media-playback-pause-symbolic"
label: FocusSession.paused ? "Resume" : "Pause"
onActivated: FocusSession.pauseOrResume()
}
FocusAction {
width: (parent.width - parent.spacing * 2) / 3
icon: "view-grid-symbolic"
iconFallback: "view-app-grid-symbolic"
label: "Workspace"
onActivated: {
ShellState.openOverview(FocusSession.workspaceId);
FocusSession.dismiss();
}
}
FocusAction {
width: (parent.width - parent.spacing * 2) / 3
icon: "process-stop-symbolic"
label: "End"
destructive: true
onActivated: FocusSession.end(false)
}
}
}
@@ -0,0 +1,98 @@
// The one Signal Glass layer surface. Transient curated events briefly take
// precedence; when they expire, an explicitly revealed focus session returns.
import Quickshell
import Quickshell.Hyprland
import Quickshell.Wayland
import QtQuick
import qs.config
import qs.services
PanelWindow {
id: root
property var modelData: null
readonly property var event: StatusEvents.activeEvent
readonly property string eventMonitor: root.event?.monitorName ?? Hyprland.focusedMonitor?.name ?? ""
readonly property bool eventBelongsHere: StatusEvents.active && (!root.eventMonitor || !root.modelData || root.modelData.name === root.eventMonitor)
readonly property bool focusBelongsHere: FocusSession.active && FocusSession.capsuleVisible
&& (!FocusSession.monitorName || !root.modelData || root.modelData.name === FocusSession.monitorName)
readonly property bool showingEvent: root.eventBelongsHere
readonly property bool requestedVisible: root.showingEvent || root.focusBelongsHere
screen: root.modelData
anchors.top: true
margins.top: Theme.barHeight + Theme.barGap * 2
exclusiveZone: 0
implicitWidth: root.showingEvent ? 388 : 438
implicitHeight: root.showingEvent ? 76 : 132
color: "transparent"
WlrLayershell.namespace: "qs-signal-glass"
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
property bool mapped: false
visible: root.mapped
onRequestedVisibleChanged: {
if (root.requestedVisible) {
unmapTimer.stop();
root.mapped = true;
entrance.restart();
} else if (root.mapped) {
unmapTimer.restart();
}
}
onShowingEventChanged: {
if (root.requestedVisible)
entrance.restart();
}
Component.onCompleted: {
if (root.requestedVisible)
root.mapped = true;
}
Timer {
id: unmapTimer
interval: Theme.durNormal
onTriggered: root.mapped = false
}
Loader {
id: content
anchors.fill: parent
sourceComponent: root.showingEvent ? eventComponent : focusComponent
opacity: root.requestedVisible ? 1 : 0
Behavior on opacity {
NumberAnimation { duration: Theme.durNormal; easing.type: Easing.OutCubic }
}
transform: Translate {
id: slide
y: root.requestedVisible ? 0 : -6
Behavior on y {
NumberAnimation { duration: Theme.durNormal; easing.type: Easing.OutCubic }
}
}
}
Component {
id: eventComponent
EventCard { event: root.event }
}
Component {
id: focusComponent
FocusCard {}
}
ParallelAnimation {
id: entrance
NumberAnimation { target: content; property: "opacity"; from: 0; to: 1; duration: Theme.durNormal; easing.type: Easing.OutCubic }
NumberAnimation { target: slide; property: "y"; from: -6; to: 0; duration: Theme.durNormal; easing.type: Easing.OutCubic }
}
}
@@ -0,0 +1,4 @@
module qs.modules.signals
EventCard 1.0 EventCard.qml
FocusCard 1.0 FocusCard.qml
SignalGlass 1.0 SignalGlass.qml