added quickshell and updated zsh
This commit is contained in:
260
home/hypr/quickshell/components/AboutMac.qml
Normal file
260
home/hypr/quickshell/components/AboutMac.qml
Normal file
@@ -0,0 +1,260 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: aboutWindow
|
||||
visible: GlobalState.aboutMacVisible
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
color: Qt.rgba(0, 0, 0, 0.35)
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.namespace: "quickshell-aboutmac"
|
||||
WlrLayershell.keyboardFocus: visible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
|
||||
// Dismiss when clicking outside modal
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: GlobalState.aboutMacVisible = false
|
||||
}
|
||||
|
||||
// Centered Dialog
|
||||
Rectangle {
|
||||
id: dialogBox
|
||||
anchors.centerIn: parent
|
||||
width: 540
|
||||
height: 330
|
||||
radius: Theme.radiusModal
|
||||
color: Theme.windowBg
|
||||
border.color: Theme.windowBorder
|
||||
border.width: 1
|
||||
|
||||
// Prevent clicking inside from dismissing
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
spacing: 12
|
||||
|
||||
// Top Traffic Lights Bar
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
// Red Close Dot
|
||||
Rectangle {
|
||||
width: 12
|
||||
height: 12
|
||||
radius: 6
|
||||
color: closeMouse.containsMouse ? "#E0443E" : "#FF5F56"
|
||||
border.color: "#E0443E"
|
||||
border.width: 0.5
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: closeMouse.containsMouse
|
||||
text: "×"
|
||||
font.pixelSize: 10
|
||||
color: "#4A0002"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: closeMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: GlobalState.aboutMacVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
// Yellow Minimize Dot
|
||||
Rectangle {
|
||||
width: 12
|
||||
height: 12
|
||||
radius: 6
|
||||
color: "#FFBD2E"
|
||||
border.color: "#DEA123"
|
||||
border.width: 0.5
|
||||
}
|
||||
|
||||
// Green Zoom Dot
|
||||
Rectangle {
|
||||
width: 12
|
||||
height: 12
|
||||
radius: 6
|
||||
color: "#27C93F"
|
||||
border.color: "#1AAB29"
|
||||
border.width: 0.5
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
Text {
|
||||
text: "Overview"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.DemiBold
|
||||
color: Theme.textSecondary
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
}
|
||||
|
||||
// Main Specs Content
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
spacing: 24
|
||||
|
||||
// Left: Catalina Island Badge
|
||||
Image {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
width: 130
|
||||
height: 130
|
||||
source: "../assets/catalina-badge.svg"
|
||||
sourceSize: Qt.size(130, 130)
|
||||
}
|
||||
|
||||
// Right: System Details
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 6
|
||||
|
||||
Text {
|
||||
text: "macOS Catalina"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 22
|
||||
font.weight: Font.Bold
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Version 10.15.7 (NixOS Edition)"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textSecondary
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
}
|
||||
|
||||
// Specs Rows
|
||||
SpecRow { label: "Host"; value: "Hades (AMD + NVIDIA RTX)" }
|
||||
SpecRow { label: "Processor"; value: "AMD High-Performance Multi-Core" }
|
||||
SpecRow { label: "Memory"; value: `${GlobalState.memTotalGb} GB RAM (${GlobalState.memUsedGb} GB in use)` }
|
||||
SpecRow { label: "Graphics"; value: "NVIDIA GeForce RTX (Proprietary Driver)" }
|
||||
SpecRow { label: "Compositor"; value: "Hyprland 0.55+ (Wayland)" }
|
||||
SpecRow { label: "Operating System"; value: "NixOS 26.05 (x86_64-linux)" }
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom Action Buttons
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignRight
|
||||
spacing: 12
|
||||
|
||||
Rectangle {
|
||||
implicitWidth: sysRepText.implicitWidth + 20
|
||||
height: 24
|
||||
radius: Theme.radiusSmall
|
||||
color: repMouse.containsMouse ? Qt.rgba(1,1,1,0.2) : Qt.rgba(1,1,1,0.1)
|
||||
border.color: Qt.rgba(1,1,1,0.15)
|
||||
border.width: 1
|
||||
|
||||
Text {
|
||||
id: sysRepText
|
||||
anchors.centerIn: parent
|
||||
text: "System Report..."
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: repMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
GlobalState.aboutMacVisible = false;
|
||||
GlobalState.launchApp("foot -e btop");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
implicitWidth: updText.implicitWidth + 20
|
||||
height: 24
|
||||
radius: Theme.radiusSmall
|
||||
color: updMouse.containsMouse ? Qt.rgba(1,1,1,0.2) : Qt.rgba(1,1,1,0.1)
|
||||
border.color: Qt.rgba(1,1,1,0.15)
|
||||
border.width: 1
|
||||
|
||||
Text {
|
||||
id: updText
|
||||
anchors.centerIn: parent
|
||||
text: "Software Update..."
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: updMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
GlobalState.aboutMacVisible = false;
|
||||
GlobalState.launchApp("foot -e zsh -c 'echo \"Checking NixOS system configuration...\"; sudo nixos-rebuild dry-activate --flake /home/anish/NixOS-Configs#hades; exec zsh'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component SpecRow: RowLayout {
|
||||
property string label: ""
|
||||
property string value: ""
|
||||
Layout.fillWidth: true
|
||||
spacing: 10
|
||||
|
||||
Text {
|
||||
text: label
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.DemiBold
|
||||
color: Theme.textSecondary
|
||||
Layout.preferredWidth: 105
|
||||
}
|
||||
|
||||
Text {
|
||||
text: value
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textPrimary
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
147
home/hypr/quickshell/components/AppMenuDropdown.qml
Normal file
147
home/hypr/quickshell/components/AppMenuDropdown.qml
Normal file
@@ -0,0 +1,147 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
property string menuName: ""
|
||||
width: 200
|
||||
implicitHeight: menuCol.implicitHeight + 12
|
||||
radius: Theme.radiusMedium
|
||||
color: Theme.menuDropdownBg
|
||||
border.color: Theme.menuDropdownBorder
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
id: menuCol
|
||||
anchors.fill: parent
|
||||
anchors.margins: 6
|
||||
spacing: 2
|
||||
|
||||
// FILE MENU
|
||||
Repeater {
|
||||
model: root.menuName === "File" ? [
|
||||
{ text: "New Window", shortcut: "⌘N", cmd: "foot &" },
|
||||
{ text: "New Incognito Window", shortcut: "⇧⌘N", cmd: "brave --incognito &" },
|
||||
{ text: "Close Window", shortcut: "⌘W", cmd: "hyprctl dispatch killactive" },
|
||||
{ text: "---", shortcut: "", cmd: "" },
|
||||
{ text: "Take Screenshot", shortcut: "⇧⌘5", cmd: "grim -g \"$(slurp)\" ~/screenshot.png" }
|
||||
] : []
|
||||
delegate: MenuEntryDelegate {}
|
||||
}
|
||||
|
||||
// EDIT MENU
|
||||
Repeater {
|
||||
model: root.menuName === "Edit" ? [
|
||||
{ text: "Undo", shortcut: "⌘Z", cmd: "" },
|
||||
{ text: "Redo", shortcut: "⇧⌘Z", cmd: "" },
|
||||
{ text: "---", shortcut: "", cmd: "" },
|
||||
{ text: "Cut", shortcut: "⌘X", cmd: "wl-copy" },
|
||||
{ text: "Copy", shortcut: "⌘C", cmd: "wl-copy" },
|
||||
{ text: "Paste", shortcut: "⌘V", cmd: "wl-paste" },
|
||||
{ text: "Select All", shortcut: "⌘A", cmd: "" }
|
||||
] : []
|
||||
delegate: MenuEntryDelegate {}
|
||||
}
|
||||
|
||||
// VIEW MENU
|
||||
Repeater {
|
||||
model: root.menuName === "View" ? [
|
||||
{ text: "Toggle Fullscreen", shortcut: "⌃⌘F", cmd: "hyprctl dispatch fullscreen 0" },
|
||||
{ text: "Toggle Floating", shortcut: "⌘V", cmd: "hyprctl dispatch togglefloating" },
|
||||
{ text: "Toggle Group", shortcut: "⌘G", cmd: "hyprctl dispatch togglegroup" },
|
||||
{ text: "---", shortcut: "", cmd: "" },
|
||||
{ text: "Zoom In", shortcut: "⌘+", cmd: "" },
|
||||
{ text: "Zoom Out", shortcut: "⌘-", cmd: "" }
|
||||
] : []
|
||||
delegate: MenuEntryDelegate {}
|
||||
}
|
||||
|
||||
// WINDOW MENU
|
||||
Repeater {
|
||||
model: root.menuName === "Window" ? [
|
||||
{ text: "Minimize Window", shortcut: "⌘M", cmd: "hyprctl dispatch movetoworkspacesilent special:scratch" },
|
||||
{ text: "Tile Left", shortcut: "⌃⌥←", cmd: "hyprctl dispatch movewindow l" },
|
||||
{ text: "Tile Right", shortcut: "⌃⌥→", cmd: "hyprctl dispatch movewindow r" },
|
||||
{ text: "---", shortcut: "", cmd: "" },
|
||||
{ text: "Show Scratchpad", shortcut: "⌘↩", cmd: "hyprctl dispatch togglespecialworkspace scratch" },
|
||||
{ text: "Show Messaging", shortcut: "⌘M", cmd: "hyprctl dispatch togglespecialworkspace messaging" }
|
||||
] : []
|
||||
delegate: MenuEntryDelegate {}
|
||||
}
|
||||
|
||||
// HELP MENU
|
||||
Repeater {
|
||||
model: root.menuName === "Help" ? [
|
||||
{ text: "Hyprland Documentation", shortcut: "", cmd: "brave https://wiki.hyprland.org &" },
|
||||
{ text: "NixOS Manual", shortcut: "", cmd: "brave https://nixos.org/manual/nixos/stable/ &" },
|
||||
{ text: "---", shortcut: "", cmd: "" },
|
||||
{ text: "About Antigravity", shortcut: "", cmd: "" }
|
||||
] : []
|
||||
delegate: MenuEntryDelegate {}
|
||||
}
|
||||
}
|
||||
|
||||
component MenuEntryDelegate: Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: modelData.text === "---" ? 7 : 22
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
visible: modelData.text === "---"
|
||||
color: "transparent"
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
visible: modelData.text !== "---"
|
||||
radius: Theme.radiusSmall
|
||||
color: itemMouse.containsMouse ? Theme.menuHoverBlue : "transparent"
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 10
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
text: modelData.text
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeNormal
|
||||
color: itemMouse.containsMouse ? Theme.menuTextHover : Theme.textPrimary
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Text {
|
||||
visible: modelData.shortcut !== ""
|
||||
text: modelData.shortcut
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: itemMouse.containsMouse ? Theme.menuTextHover : Theme.textTertiary
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: itemMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
GlobalState.activeDropdownMenu = "";
|
||||
if (modelData.cmd) {
|
||||
GlobalState.launchApp(modelData.cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
158
home/hypr/quickshell/components/AppleMenu.qml
Normal file
158
home/hypr/quickshell/components/AppleMenu.qml
Normal file
@@ -0,0 +1,158 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
width: 220
|
||||
implicitHeight: menuColumn.implicitHeight + 12
|
||||
radius: Theme.radiusMedium
|
||||
color: Theme.menuDropdownBg
|
||||
border.color: Theme.menuDropdownBorder
|
||||
border.width: 1
|
||||
|
||||
// Drop shadow
|
||||
layer.enabled: true
|
||||
|
||||
ColumnLayout {
|
||||
id: menuColumn
|
||||
anchors.fill: parent
|
||||
anchors.margins: 6
|
||||
spacing: 2
|
||||
|
||||
// About This Mac
|
||||
MenuItem {
|
||||
text: "About This Mac"
|
||||
onTriggered: {
|
||||
GlobalState.appleMenuVisible = false;
|
||||
GlobalState.toggleAboutMac();
|
||||
}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
MenuItem {
|
||||
text: "System Preferences..."
|
||||
onTriggered: {
|
||||
GlobalState.launchApp("pavucontrol");
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "App Store..."
|
||||
onTriggered: {
|
||||
GlobalState.launchApp("foot -e zsh -c 'echo NixOS Packages; nix-env -qaP | head -n 50; exec zsh'");
|
||||
}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
MenuItem {
|
||||
text: "Activity Monitor"
|
||||
shortcut: "⌥⌘Esc"
|
||||
onTriggered: {
|
||||
GlobalState.launchApp("foot -e btop");
|
||||
}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
MenuItem {
|
||||
text: "Sleep"
|
||||
onTriggered: {
|
||||
GlobalState.appleMenuVisible = false;
|
||||
GlobalState.launchApp("systemctl suspend");
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Restart..."
|
||||
onTriggered: {
|
||||
GlobalState.appleMenuVisible = false;
|
||||
GlobalState.launchApp("systemctl reboot");
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Shut Down..."
|
||||
onTriggered: {
|
||||
GlobalState.appleMenuVisible = false;
|
||||
GlobalState.launchApp("systemctl poweroff");
|
||||
}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
MenuItem {
|
||||
text: "Lock Screen"
|
||||
shortcut: "⌃⌘Q"
|
||||
onTriggered: {
|
||||
GlobalState.appleMenuVisible = false;
|
||||
GlobalState.launchApp("hyprlock");
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Log Out anish..."
|
||||
shortcut: "⇧⌘Q"
|
||||
onTriggered: {
|
||||
GlobalState.appleMenuVisible = false;
|
||||
GlobalState.launchApp("hyprctl dispatch exit");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component MenuItem: Rectangle {
|
||||
id: itemRoot
|
||||
property string text: ""
|
||||
property string shortcut: ""
|
||||
signal triggered()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 22
|
||||
radius: Theme.radiusSmall
|
||||
color: mouseArea.containsMouse ? Theme.menuHoverBlue : "transparent"
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 10
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
text: itemRoot.text
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeNormal
|
||||
color: mouseArea.containsMouse ? Theme.menuTextHover : Theme.textPrimary
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Text {
|
||||
visible: itemRoot.shortcut !== ""
|
||||
text: itemRoot.shortcut
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: mouseArea.containsMouse ? Theme.menuTextHover : Theme.textTertiary
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: itemRoot.triggered()
|
||||
}
|
||||
}
|
||||
|
||||
component MenuSeparator: Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
Layout.topMargin: 3
|
||||
Layout.bottomMargin: 3
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
}
|
||||
}
|
||||
102
home/hypr/quickshell/components/BatteryPopup.qml
Normal file
102
home/hypr/quickshell/components/BatteryPopup.qml
Normal file
@@ -0,0 +1,102 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
width: 240
|
||||
implicitHeight: batCol.implicitHeight + 24
|
||||
radius: Theme.radiusMedium
|
||||
color: Theme.menuDropdownBg
|
||||
border.color: Theme.menuDropdownBorder
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
id: batCol
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 8
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
text: "Battery"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeNormal
|
||||
font.weight: Font.DemiBold
|
||||
color: Theme.textPrimary
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Text {
|
||||
text: `${GlobalState.batteryPercent}%`
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.DemiBold
|
||||
color: GlobalState.batteryPercent <= 20 ? Theme.accentRed : Theme.accentGreen
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 3
|
||||
|
||||
Text {
|
||||
text: GlobalState.batteryPresent
|
||||
? (GlobalState.batteryCharging ? "Power Source: Power Adapter" : "Power Source: Battery")
|
||||
: "Power Source: AC Connected"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
Text {
|
||||
text: GlobalState.batteryPresent
|
||||
? `Status: ${GlobalState.batteryStatus}`
|
||||
: "Desktop Workstation Mode"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textSecondary
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 24
|
||||
radius: Theme.radiusSmall
|
||||
color: batPrefMouse.containsMouse ? Qt.rgba(1.0, 1.0, 1.0, 0.15) : Qt.rgba(1.0, 1.0, 1.0, 0.08)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "Energy Saver Preferences..."
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: batPrefMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
GlobalState.batteryPopupVisible = false;
|
||||
GlobalState.launchApp("foot -e btop");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
94
home/hypr/quickshell/components/CalendarPopup.qml
Normal file
94
home/hypr/quickshell/components/CalendarPopup.qml
Normal file
@@ -0,0 +1,94 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
width: 250
|
||||
implicitHeight: calCol.implicitHeight + 24
|
||||
radius: Theme.radiusMedium
|
||||
color: Theme.menuDropdownBg
|
||||
border.color: Theme.menuDropdownBorder
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
id: calCol
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 10
|
||||
|
||||
Text {
|
||||
text: GlobalState.fullDateString
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeNormal
|
||||
font.weight: Font.DemiBold
|
||||
color: Theme.textPrimary
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: GlobalState.timeString
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 22
|
||||
font.weight: Font.Light
|
||||
color: Theme.accentBlue
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
}
|
||||
|
||||
// Days grid header
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Repeater {
|
||||
model: ["S", "M", "T", "W", "T", "F", "S"]
|
||||
delegate: Text {
|
||||
text: modelData
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.DemiBold
|
||||
color: Theme.textTertiary
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Quick mini-calendar representation
|
||||
GridLayout {
|
||||
id: gridDays
|
||||
columns: 7
|
||||
Layout.fillWidth: true
|
||||
rowSpacing: 4
|
||||
columnSpacing: 4
|
||||
|
||||
readonly property var todayDate: new Date()
|
||||
readonly property int currentDay: todayDate.getDate()
|
||||
|
||||
Repeater {
|
||||
model: 31
|
||||
delegate: Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 22
|
||||
radius: 11
|
||||
color: (index + 1) === gridDays.currentDay ? Theme.accentBlue : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: `${index + 1}`
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: (index + 1) === gridDays.currentDay ? Font.Bold : Font.Normal
|
||||
color: (index + 1) === gridDays.currentDay ? "#FFFFFF" : Theme.textSecondary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
638
home/hypr/quickshell/components/ControlCenter.qml
Normal file
638
home/hypr/quickshell/components/ControlCenter.qml
Normal file
@@ -0,0 +1,638 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: ccWindow
|
||||
visible: GlobalState.controlCenterVisible
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
margins {
|
||||
top: Theme.menuBarHeight
|
||||
}
|
||||
|
||||
implicitWidth: 360
|
||||
color: "transparent"
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.namespace: "quickshell-controlcenter"
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
property int activeTab: 0 // 0 = Today, 1 = Notifications
|
||||
|
||||
// Sidebar Container
|
||||
Rectangle {
|
||||
id: sidebarPanel
|
||||
anchors.fill: parent
|
||||
color: Theme.windowBg
|
||||
border.color: Theme.windowBorder
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 14
|
||||
spacing: 12
|
||||
|
||||
// =================================================================
|
||||
// TAB SWITCHER (Today | Notifications)
|
||||
// =================================================================
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 30
|
||||
radius: Theme.radiusMedium
|
||||
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
// Today Tab Button
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
radius: Theme.radiusMedium
|
||||
color: ccWindow.activeTab === 0 ? Qt.rgba(1.0, 1.0, 1.0, 0.18) : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "Today"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeNormal
|
||||
font.weight: ccWindow.activeTab === 0 ? Font.DemiBold : Font.Normal
|
||||
color: ccWindow.activeTab === 0 ? "#FFFFFF" : Theme.textTertiary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: ccWindow.activeTab = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Notifications Tab Button
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
radius: Theme.radiusMedium
|
||||
color: ccWindow.activeTab === 1 ? Qt.rgba(1.0, 1.0, 1.0, 0.18) : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "Notifications"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeNormal
|
||||
font.weight: ccWindow.activeTab === 1 ? Font.DemiBold : Font.Normal
|
||||
color: ccWindow.activeTab === 1 ? "#FFFFFF" : Theme.textTertiary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: ccWindow.activeTab = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// TAB 1: TODAY VIEW
|
||||
// =================================================================
|
||||
ScrollView {
|
||||
visible: ccWindow.activeTab === 0
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
clip: true
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: 12
|
||||
|
||||
// 1. Large Date & Time Widget
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 70
|
||||
radius: Theme.radiusLarge
|
||||
color: Theme.cardBg
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
text: GlobalState.fullDateString
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.DemiBold
|
||||
color: Theme.accentBlue
|
||||
}
|
||||
|
||||
Text {
|
||||
text: GlobalState.timeString
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 26
|
||||
font.weight: Font.Light
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Control Toggles (Wi-Fi, Bluetooth, DND, Night Shift)
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 120
|
||||
radius: Theme.radiusLarge
|
||||
color: Theme.cardBg
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
|
||||
GridLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
columns: 2
|
||||
rowSpacing: 8
|
||||
columnSpacing: 8
|
||||
|
||||
// Wi-Fi Toggle
|
||||
ToggleCard {
|
||||
iconSource: "../assets/wifi.svg"
|
||||
title: "Wi-Fi"
|
||||
subtitle: GlobalState.wifiSsid
|
||||
isActive: GlobalState.wifiConnected
|
||||
onClicked: GlobalState.launchApp("nm-connection-editor || foot -e nmtui")
|
||||
}
|
||||
|
||||
// Bluetooth Toggle
|
||||
ToggleCard {
|
||||
iconSource: "../assets/bluetooth.svg"
|
||||
title: "Bluetooth"
|
||||
subtitle: "Active"
|
||||
isActive: true
|
||||
onClicked: GlobalState.launchApp("foot -e bluetoothctl")
|
||||
}
|
||||
|
||||
// Do Not Disturb Toggle
|
||||
ToggleCard {
|
||||
iconSource: "../assets/preferences.svg"
|
||||
title: "Do Not Disturb"
|
||||
subtitle: "Off"
|
||||
isActive: false
|
||||
onClicked: {}
|
||||
}
|
||||
|
||||
// Sound Mute Toggle
|
||||
ToggleCard {
|
||||
iconSource: "../assets/volume.svg"
|
||||
title: "Sound"
|
||||
subtitle: GlobalState.volumeMuted ? "Muted" : `${GlobalState.volume}%`
|
||||
isActive: !GlobalState.volumeMuted
|
||||
onClicked: GlobalState.toggleVolumeMute()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Brightness & Volume Sliders
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 110
|
||||
radius: Theme.radiusLarge
|
||||
color: Theme.cardBg
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 10
|
||||
|
||||
// Display Brightness Slider
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Image {
|
||||
width: 16
|
||||
height: 16
|
||||
source: "../assets/brightness.svg"
|
||||
sourceSize: Qt.size(16, 16)
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
height: 18
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 9
|
||||
color: Qt.rgba(1,1,1,0.18)
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width * (GlobalState.brightness / 100.0)
|
||||
radius: 9
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
function update(m) {
|
||||
const frac = Math.max(0.01, Math.min(1.0, m.x / width));
|
||||
GlobalState.setBrightness(Math.round(frac * 100));
|
||||
}
|
||||
onPressed: (m) => update(m)
|
||||
onPositionChanged: (m) => { if (pressed) update(m); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sound Volume Slider
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Image {
|
||||
width: 16
|
||||
height: 16
|
||||
source: "../assets/volume.svg"
|
||||
sourceSize: Qt.size(16, 16)
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
height: 18
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 9
|
||||
color: Qt.rgba(1,1,1,0.18)
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width * (GlobalState.volume / 100.0)
|
||||
radius: 9
|
||||
color: Theme.accentBlue
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
function update(m) {
|
||||
const frac = Math.max(0.0, Math.min(1.0, m.x / width));
|
||||
GlobalState.setVolume(Math.round(frac * 100));
|
||||
}
|
||||
onPressed: (m) => update(m)
|
||||
onPositionChanged: (m) => { if (pressed) update(m); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. System Resources Monitor Widget
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 90
|
||||
radius: Theme.radiusLarge
|
||||
color: Theme.cardBg
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 6
|
||||
|
||||
Text {
|
||||
text: "System Performance"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.DemiBold
|
||||
color: Theme.textSecondary
|
||||
}
|
||||
|
||||
// CPU Bar
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
Text {
|
||||
text: "CPU"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textPrimary
|
||||
Layout.preferredWidth: 32
|
||||
}
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 6
|
||||
radius: 3
|
||||
color: Qt.rgba(1,1,1,0.15)
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width * (GlobalState.cpuPercent / 100.0)
|
||||
radius: 3
|
||||
color: GlobalState.cpuPercent > 80 ? Theme.accentRed : Theme.accentGreen
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: `${GlobalState.cpuPercent}%`
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textSecondary
|
||||
Layout.preferredWidth: 36
|
||||
horizontalAlignment: Text.AlignRight
|
||||
}
|
||||
}
|
||||
|
||||
// Memory Bar
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
Text {
|
||||
text: "RAM"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textPrimary
|
||||
Layout.preferredWidth: 32
|
||||
}
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 6
|
||||
radius: 3
|
||||
color: Qt.rgba(1,1,1,0.15)
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width * (GlobalState.memPercent / 100.0)
|
||||
radius: 3
|
||||
color: Theme.accentBlue
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: `${GlobalState.memUsedGb}G`
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textSecondary
|
||||
Layout.preferredWidth: 36
|
||||
horizontalAlignment: Text.AlignRight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Now Playing Media Widget
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 80
|
||||
radius: Theme.radiusLarge
|
||||
color: Theme.cardBg
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 10
|
||||
|
||||
Image {
|
||||
width: 36
|
||||
height: 36
|
||||
source: "../assets/music.svg"
|
||||
sourceSize: Qt.size(36, 36)
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
text: GlobalState.mediaTitle || "No Media Playing"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeNormal
|
||||
font.weight: Font.Medium
|
||||
color: "#FFFFFF"
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Text {
|
||||
text: GlobalState.mediaArtist || "Apple Music"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textTertiary
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
// Playback controls
|
||||
RowLayout {
|
||||
spacing: 4
|
||||
|
||||
Rectangle {
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 12
|
||||
color: Qt.rgba(1,1,1,0.1)
|
||||
Text { anchors.centerIn: parent; text: "⏮"; color: "#FFFFFF"; font.pixelSize: 10 }
|
||||
MouseArea { anchors.fill: parent; cursorShape: Qt.PointingHandCursor; onClicked: GlobalState.mediaPrevious() }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 28
|
||||
height: 28
|
||||
radius: 14
|
||||
color: Theme.accentBlue
|
||||
Text { anchors.centerIn: parent; text: GlobalState.mediaPlaying ? "⏸" : "▶"; color: "#FFFFFF"; font.pixelSize: 11 }
|
||||
MouseArea { anchors.fill: parent; cursorShape: Qt.PointingHandCursor; onClicked: GlobalState.mediaPlayPause() }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 12
|
||||
color: Qt.rgba(1,1,1,0.1)
|
||||
Text { anchors.centerIn: parent; text: "⏭"; color: "#FFFFFF"; font.pixelSize: 10 }
|
||||
MouseArea { anchors.fill: parent; cursorShape: Qt.PointingHandCursor; onClicked: GlobalState.mediaNext() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// TAB 2: NOTIFICATIONS VIEW
|
||||
// =================================================================
|
||||
ColumnLayout {
|
||||
visible: ccWindow.activeTab === 1
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
spacing: 12
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
text: "Notifications"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.DemiBold
|
||||
color: "#FFFFFF"
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Rectangle {
|
||||
implicitWidth: clearText.implicitWidth + 12
|
||||
height: 22
|
||||
radius: Theme.radiusSmall
|
||||
color: Qt.rgba(1,1,1,0.12)
|
||||
Text {
|
||||
id: clearText
|
||||
anchors.centerIn: parent
|
||||
text: "Clear All"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textSecondary
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Placeholder / Active notifications card
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 70
|
||||
radius: Theme.radiusLarge
|
||||
color: Theme.cardBg
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 10
|
||||
|
||||
Image {
|
||||
width: 28
|
||||
height: 28
|
||||
source: "../assets/apple.svg"
|
||||
sourceSize: Qt.size(28, 28)
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
text: "macOS Catalina on Hyprland"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeNormal
|
||||
font.weight: Font.Medium
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Quickshell desktop loaded successfully."
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textSecondary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle Card Component
|
||||
component ToggleCard: Rectangle {
|
||||
id: cardRoot
|
||||
property string iconSource: ""
|
||||
property string title: ""
|
||||
property string subtitle: ""
|
||||
property bool isActive: false
|
||||
signal clicked()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 46
|
||||
radius: Theme.radiusMedium
|
||||
color: cardMouse.containsMouse ? Qt.rgba(1.0, 1.0, 1.0, 0.22) : Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
spacing: 8
|
||||
|
||||
Rectangle {
|
||||
width: 28
|
||||
height: 28
|
||||
radius: 14
|
||||
color: cardRoot.isActive ? Theme.accentBlue : Qt.rgba(1,1,1,0.2)
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 14
|
||||
height: 14
|
||||
source: cardRoot.iconSource
|
||||
sourceSize: Qt.size(14, 14)
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 1
|
||||
|
||||
Text {
|
||||
text: cardRoot.title
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: "#FFFFFF"
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Text {
|
||||
text: cardRoot.subtitle
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 10
|
||||
color: Theme.textTertiary
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: cardMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: cardRoot.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
338
home/hypr/quickshell/components/Dock.qml
Normal file
338
home/hypr/quickshell/components/Dock.qml
Normal file
@@ -0,0 +1,338 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: dockWindow
|
||||
property var modelData
|
||||
screen: modelData
|
||||
|
||||
anchors {
|
||||
bottom: true
|
||||
}
|
||||
|
||||
margins {
|
||||
bottom: 6
|
||||
}
|
||||
|
||||
// Adjust width to fit content
|
||||
implicitWidth: dockTray.implicitWidth + 32
|
||||
implicitHeight: 90
|
||||
|
||||
color: "transparent"
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
WlrLayershell.namespace: "quickshell-dock"
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
// Reserve 70px exclusive zone so windows don't overlap the dock
|
||||
exclusiveZone: 70
|
||||
|
||||
// Tooltip overlay container
|
||||
Item {
|
||||
id: tooltipContainer
|
||||
anchors.fill: parent
|
||||
z: 100
|
||||
}
|
||||
|
||||
// 2.5D Frosted Glass Dock Tray
|
||||
Rectangle {
|
||||
id: dockTray
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
implicitWidth: dockLayout.implicitWidth + 24
|
||||
height: 68
|
||||
radius: Theme.radiusDock
|
||||
color: Theme.dockBg
|
||||
border.color: Theme.dockBorder
|
||||
border.width: 1
|
||||
|
||||
// Top glossy reflection edge line (Catalina shelf characteristic)
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.leftMargin: 12
|
||||
anchors.rightMargin: 12
|
||||
height: 1
|
||||
color: Theme.dockHighlight
|
||||
opacity: 0.8
|
||||
}
|
||||
|
||||
// Inner items layout
|
||||
RowLayout {
|
||||
id: dockLayout
|
||||
anchors.centerIn: parent
|
||||
spacing: 6
|
||||
|
||||
// =================================================================
|
||||
// 1. PINNED APPS
|
||||
// =================================================================
|
||||
DockItem {
|
||||
id: finderItem
|
||||
name: "Finder"
|
||||
iconSource: "../assets/finder.svg"
|
||||
execCmd: "foot -e sh -c 'cd ~; lf || yazi || ls -la; exec zsh'"
|
||||
appClass: "foot"
|
||||
isPinned: true
|
||||
}
|
||||
|
||||
DockItem {
|
||||
name: "Launchpad"
|
||||
iconSource: "../assets/launchpad.svg"
|
||||
execCmd: ""
|
||||
isPinned: true
|
||||
onCustomClicked: GlobalState.toggleSpotlight()
|
||||
}
|
||||
|
||||
DockItem {
|
||||
name: "Brave Browser"
|
||||
iconSource: "../assets/browser.svg"
|
||||
execCmd: "brave"
|
||||
appClass: "brave-browser"
|
||||
isPinned: true
|
||||
}
|
||||
|
||||
DockItem {
|
||||
name: "Terminal"
|
||||
iconSource: "../assets/terminal.svg"
|
||||
execCmd: "foot"
|
||||
appClass: "foot"
|
||||
isPinned: true
|
||||
}
|
||||
|
||||
DockItem {
|
||||
name: "Neovim"
|
||||
iconSource: "../assets/code.svg"
|
||||
execCmd: "foot -e nvim"
|
||||
appClass: "nvim"
|
||||
isPinned: true
|
||||
}
|
||||
|
||||
DockItem {
|
||||
name: "System Preferences"
|
||||
iconSource: "../assets/preferences.svg"
|
||||
execCmd: "pavucontrol"
|
||||
appClass: "pavucontrol"
|
||||
isPinned: true
|
||||
}
|
||||
|
||||
DockItem {
|
||||
name: "App Store"
|
||||
iconSource: "../assets/appstore.svg"
|
||||
execCmd: "foot -e zsh -c 'echo NixOS Packages; nix-env -qaP | head -n 50; exec zsh'"
|
||||
appClass: ""
|
||||
isPinned: true
|
||||
}
|
||||
|
||||
DockItem {
|
||||
name: "Music"
|
||||
iconSource: "../assets/music.svg"
|
||||
execCmd: ""
|
||||
appClass: ""
|
||||
isPinned: true
|
||||
onCustomClicked: GlobalState.mediaPlayPause()
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// 2. DYNAMIC RUNNING APPS (Not pinned)
|
||||
// =================================================================
|
||||
Repeater {
|
||||
model: {
|
||||
const pinnedClasses = ["foot", "brave-browser", "pavucontrol", "nvim"];
|
||||
const list = [];
|
||||
const seen = {};
|
||||
if (Array.isArray(GlobalState.runningApps)) {
|
||||
for (let i = 0; i < GlobalState.runningApps.length; i++) {
|
||||
const client = GlobalState.runningApps[i];
|
||||
const cls = (client.class || "").toLowerCase();
|
||||
if (cls && !pinnedClasses.includes(cls) && !seen[cls]) {
|
||||
seen[cls] = true;
|
||||
list.push({
|
||||
name: client.title || client.class || "App",
|
||||
cls: client.class,
|
||||
address: client.address
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
delegate: DockItem {
|
||||
required property var modelData
|
||||
name: modelData.name
|
||||
iconSource: "../assets/code.svg"
|
||||
appClass: modelData.cls
|
||||
isPinned: false
|
||||
onCustomClicked: {
|
||||
if (modelData.address) {
|
||||
Hyprland.dispatch(`focuswindow address:${modelData.address}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// 3. DOCK SEPARATOR DIVIDER
|
||||
// =================================================================
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 1
|
||||
Layout.preferredHeight: 44
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.leftMargin: 4
|
||||
Layout.rightMargin: 4
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.22)
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// 4. DOWNLOADS FOLDER & TRASH
|
||||
// =================================================================
|
||||
DockItem {
|
||||
name: "Downloads"
|
||||
iconSource: "../assets/folder-downloads.svg"
|
||||
execCmd: "foot -e sh -c 'cd ~/Downloads; ls -la; exec zsh'"
|
||||
isPinned: true
|
||||
}
|
||||
|
||||
DockItem {
|
||||
name: "Trash"
|
||||
iconSource: "../assets/trash-empty.svg"
|
||||
execCmd: "foot -e sh -c 'cd ~/.local/share/Trash/files 2>/dev/null || cd ~; ls -la; exec zsh'"
|
||||
isPinned: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reusable Dock Item Component
|
||||
component DockItem: Item {
|
||||
id: itemRoot
|
||||
property string name: ""
|
||||
property string iconSource: ""
|
||||
property string execCmd: ""
|
||||
property string appClass: ""
|
||||
property bool isPinned: true
|
||||
signal customClicked()
|
||||
|
||||
// Check if app is running
|
||||
readonly property bool isRunning: {
|
||||
if (!itemRoot.appClass) return false;
|
||||
const target = itemRoot.appClass.toLowerCase();
|
||||
if (GlobalState.activeWindowClass.toLowerCase().includes(target)) return true;
|
||||
if (Array.isArray(GlobalState.runningApps)) {
|
||||
for (let i = 0; i < GlobalState.runningApps.length; i++) {
|
||||
const c = GlobalState.runningApps[i];
|
||||
if ((c.class || "").toLowerCase().includes(target)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
implicitWidth: 50
|
||||
implicitHeight: 64
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
|
||||
// Container with scale & bounce transform
|
||||
Item {
|
||||
id: iconWrapper
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 8
|
||||
width: 48
|
||||
height: 48
|
||||
|
||||
scale: itemArea.containsMouse ? 1.28 : 1.0
|
||||
y: itemArea.containsMouse ? -8 : 0
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: 180; easing.type: Easing.OutCubic }
|
||||
}
|
||||
Behavior on y {
|
||||
NumberAnimation { duration: 180; easing.type: Easing.OutCubic }
|
||||
}
|
||||
|
||||
// Icon Image
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 46
|
||||
height: 46
|
||||
source: itemRoot.iconSource
|
||||
sourceSize: Qt.size(92, 92)
|
||||
smooth: true
|
||||
mipmap: true
|
||||
}
|
||||
|
||||
// Click Bounce Sequential Animation
|
||||
SequentialAnimation {
|
||||
id: bounceAnim
|
||||
NumberAnimation { target: iconWrapper; property: "y"; to: -24; duration: 150; easing.type: Easing.OutQuad }
|
||||
NumberAnimation { target: iconWrapper; property: "y"; to: -4; duration: 130; easing.type: Easing.InQuad }
|
||||
NumberAnimation { target: iconWrapper; property: "y"; to: -14; duration: 100; easing.type: Easing.OutQuad }
|
||||
NumberAnimation { target: iconWrapper; property: "y"; to: 0; duration: 100; easing.type: Easing.InQuad }
|
||||
}
|
||||
}
|
||||
|
||||
// Active App Running Indicator Dot (White glowing pill)
|
||||
Rectangle {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 2
|
||||
width: 4
|
||||
height: 4
|
||||
radius: 2
|
||||
color: Theme.dockDot
|
||||
visible: itemRoot.isRunning
|
||||
}
|
||||
|
||||
// Hover Tooltip Badge (macOS Catalina Style Black Pill)
|
||||
Rectangle {
|
||||
id: tooltipPill
|
||||
visible: itemArea.containsMouse
|
||||
opacity: itemArea.containsMouse ? 1.0 : 0.0
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: 6
|
||||
implicitWidth: tooltipText.implicitWidth + 16
|
||||
height: 24
|
||||
radius: 6
|
||||
color: Qt.rgba(0.08, 0.08, 0.10, 0.92)
|
||||
border.color: Qt.rgba(1.0, 1.0, 1.0, 0.18)
|
||||
border.width: 1
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 120 }
|
||||
}
|
||||
|
||||
Text {
|
||||
id: tooltipText
|
||||
anchors.centerIn: parent
|
||||
text: itemRoot.name
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse interaction
|
||||
MouseArea {
|
||||
id: itemArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
bounceAnim.start();
|
||||
if (itemRoot.execCmd !== "") {
|
||||
GlobalState.launchApp(itemRoot.execCmd);
|
||||
} else {
|
||||
itemRoot.customClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
507
home/hypr/quickshell/components/MenuBar.qml
Normal file
507
home/hypr/quickshell/components/MenuBar.qml
Normal file
@@ -0,0 +1,507 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Services.SystemTray
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: menuBarWindow
|
||||
property var modelData
|
||||
screen: modelData
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
|
||||
// Set implicitHeight to accommodate bar + open popups without clipping
|
||||
implicitHeight: (GlobalState.appleMenuVisible || GlobalState.activeDropdownMenu !== "" ||
|
||||
GlobalState.volumePopupVisible || GlobalState.wifiPopupVisible ||
|
||||
GlobalState.batteryPopupVisible || GlobalState.calendarPopupVisible) ? 420 : Theme.menuBarHeight
|
||||
|
||||
color: "transparent"
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
WlrLayershell.namespace: "quickshell-menubar"
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
// Set exclusive zone only for the 26px bar
|
||||
exclusiveZone: Theme.menuBarHeight
|
||||
|
||||
// Background Bar (26px)
|
||||
Rectangle {
|
||||
id: barRect
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: Theme.menuBarHeight
|
||||
color: Theme.menuBarBg
|
||||
border.color: Theme.menuBarBorder
|
||||
border.width: 0
|
||||
|
||||
// Bottom hairline border
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
height: 1
|
||||
color: Theme.menuBarBorder
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 12
|
||||
anchors.rightMargin: 12
|
||||
spacing: 0
|
||||
|
||||
// =================================================================
|
||||
// LEFT SIDE: Apple Menu + App Title + Standard Menus
|
||||
// =================================================================
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||
spacing: 2
|
||||
|
||||
// Apple Logo Button
|
||||
Rectangle {
|
||||
id: appleBtn
|
||||
width: 28
|
||||
height: 20
|
||||
radius: Theme.radiusSmall
|
||||
color: (GlobalState.appleMenuVisible || appleMouse.containsMouse)
|
||||
? Qt.rgba(1.0, 1.0, 1.0, 0.18) : "transparent"
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 14
|
||||
height: 14
|
||||
source: "../assets/apple.svg"
|
||||
sourceSize: Qt.size(14, 14)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: appleMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
const wasOpen = GlobalState.appleMenuVisible;
|
||||
GlobalState.closeAllPopups();
|
||||
GlobalState.appleMenuVisible = !wasOpen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Active App Title (Bold)
|
||||
Rectangle {
|
||||
id: appTitleBtn
|
||||
implicitWidth: appTitleText.implicitWidth + 16
|
||||
height: 20
|
||||
radius: Theme.radiusSmall
|
||||
color: titleMouse.containsMouse ? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
||||
|
||||
Text {
|
||||
id: appTitleText
|
||||
anchors.centerIn: parent
|
||||
text: GlobalState.activeWindowClass || "Finder"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeMenuBar
|
||||
font.weight: Font.Bold
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: titleMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
const wasOpen = (GlobalState.activeDropdownMenu === "File");
|
||||
GlobalState.closeAllPopups();
|
||||
GlobalState.activeDropdownMenu = wasOpen ? "" : "File";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Standard Menus: File, Edit, View, Window, Help
|
||||
Repeater {
|
||||
model: ["File", "Edit", "View", "Window", "Help"]
|
||||
delegate: Rectangle {
|
||||
id: menuBtn
|
||||
implicitWidth: menuText.implicitWidth + 14
|
||||
height: 20
|
||||
radius: Theme.radiusSmall
|
||||
color: (GlobalState.activeDropdownMenu === modelData || menuMouse.containsMouse)
|
||||
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
||||
|
||||
Text {
|
||||
id: menuText
|
||||
anchors.centerIn: parent
|
||||
text: modelData
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeMenuBar
|
||||
font.weight: Font.Normal
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: menuMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: {
|
||||
// If a menu is already open, hovering switches to this one
|
||||
if (GlobalState.activeDropdownMenu !== "") {
|
||||
GlobalState.activeDropdownMenu = modelData;
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
const wasOpen = (GlobalState.activeDropdownMenu === modelData);
|
||||
GlobalState.closeAllPopups();
|
||||
GlobalState.activeDropdownMenu = wasOpen ? "" : modelData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spacer
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// RIGHT SIDE: Tray + Media + Volume + Wifi + Battery + Spotlight + Control Center + Clock
|
||||
// =================================================================
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
spacing: 4
|
||||
|
||||
// System Tray Icons
|
||||
Repeater {
|
||||
model: SystemTray.items
|
||||
delegate: Rectangle {
|
||||
required property SystemTrayItem modelData
|
||||
width: 22
|
||||
height: 20
|
||||
radius: Theme.radiusSmall
|
||||
color: trayMouse.containsMouse ? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 15
|
||||
height: 15
|
||||
source: modelData.icon || ""
|
||||
sourceSize: Qt.size(15, 15)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: trayMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: modelData.activate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Media Indicator (visible if playing)
|
||||
Rectangle {
|
||||
visible: GlobalState.mediaPlaying
|
||||
implicitWidth: mediaRow.implicitWidth + 12
|
||||
height: 20
|
||||
radius: Theme.radiusSmall
|
||||
color: mediaMouse.containsMouse ? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
||||
|
||||
RowLayout {
|
||||
id: mediaRow
|
||||
anchors.centerIn: parent
|
||||
spacing: 4
|
||||
Image {
|
||||
width: 13
|
||||
height: 13
|
||||
source: "../assets/music.svg"
|
||||
sourceSize: Qt.size(13, 13)
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.mediaTitle ? `${GlobalState.mediaTitle.substring(0, 18)}...` : "Playing"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textSecondary
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mediaMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: GlobalState.mediaPlayPause()
|
||||
}
|
||||
}
|
||||
|
||||
// Volume Item
|
||||
Rectangle {
|
||||
id: volBtn
|
||||
width: 26
|
||||
height: 20
|
||||
radius: Theme.radiusSmall
|
||||
color: (GlobalState.volumePopupVisible || volMouse.containsMouse)
|
||||
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 14
|
||||
height: 14
|
||||
source: "../assets/volume.svg"
|
||||
sourceSize: Qt.size(14, 14)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: volMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
const wasOpen = GlobalState.volumePopupVisible;
|
||||
GlobalState.closeAllPopups();
|
||||
GlobalState.volumePopupVisible = !wasOpen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wi-Fi Item
|
||||
Rectangle {
|
||||
id: wifiBtn
|
||||
width: 26
|
||||
height: 20
|
||||
radius: Theme.radiusSmall
|
||||
color: (GlobalState.wifiPopupVisible || wifiMouse.containsMouse)
|
||||
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 14
|
||||
height: 14
|
||||
source: "../assets/wifi.svg"
|
||||
sourceSize: Qt.size(14, 14)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: wifiMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
const wasOpen = GlobalState.wifiPopupVisible;
|
||||
GlobalState.closeAllPopups();
|
||||
GlobalState.wifiPopupVisible = !wasOpen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Battery Item
|
||||
Rectangle {
|
||||
id: batBtn
|
||||
implicitWidth: batRow.implicitWidth + 8
|
||||
height: 20
|
||||
radius: Theme.radiusSmall
|
||||
color: (GlobalState.batteryPopupVisible || batMouse.containsMouse)
|
||||
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
||||
|
||||
RowLayout {
|
||||
id: batRow
|
||||
anchors.centerIn: parent
|
||||
spacing: 4
|
||||
|
||||
Text {
|
||||
visible: GlobalState.batteryPresent
|
||||
text: `${GlobalState.batteryPercent}%`
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
Image {
|
||||
width: 18
|
||||
height: 12
|
||||
source: "../assets/battery.svg"
|
||||
sourceSize: Qt.size(18, 12)
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: batMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
const wasOpen = GlobalState.batteryPopupVisible;
|
||||
GlobalState.closeAllPopups();
|
||||
GlobalState.batteryPopupVisible = !wasOpen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spotlight Search Button
|
||||
Rectangle {
|
||||
id: spotBtn
|
||||
width: 26
|
||||
height: 20
|
||||
radius: Theme.radiusSmall
|
||||
color: (GlobalState.spotlightVisible || spotMouse.containsMouse)
|
||||
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 14
|
||||
height: 14
|
||||
source: "../assets/spotlight.svg"
|
||||
sourceSize: Qt.size(14, 14)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: spotMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: GlobalState.toggleSpotlight()
|
||||
}
|
||||
}
|
||||
|
||||
// Control Center / Notification Center Toggle Button
|
||||
Rectangle {
|
||||
id: ccBtn
|
||||
width: 26
|
||||
height: 20
|
||||
radius: Theme.radiusSmall
|
||||
color: (GlobalState.controlCenterVisible || ccMouse.containsMouse)
|
||||
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 14
|
||||
height: 14
|
||||
source: "../assets/controlcenter.svg"
|
||||
sourceSize: Qt.size(14, 14)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: ccMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: GlobalState.toggleControlCenter()
|
||||
}
|
||||
}
|
||||
|
||||
// Date & Time (Clock)
|
||||
Rectangle {
|
||||
id: clockBtn
|
||||
implicitWidth: clockRow.implicitWidth + 10
|
||||
height: 20
|
||||
radius: Theme.radiusSmall
|
||||
color: (GlobalState.calendarPopupVisible || clockMouse.containsMouse)
|
||||
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
||||
|
||||
RowLayout {
|
||||
id: clockRow
|
||||
anchors.centerIn: parent
|
||||
spacing: 6
|
||||
|
||||
Text {
|
||||
text: GlobalState.dateString
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeMenuBar
|
||||
color: Theme.textSecondary
|
||||
}
|
||||
|
||||
Text {
|
||||
text: GlobalState.timeString
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeMenuBar
|
||||
font.weight: Font.Medium
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: clockMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
const wasOpen = GlobalState.calendarPopupVisible;
|
||||
GlobalState.closeAllPopups();
|
||||
GlobalState.calendarPopupVisible = !wasOpen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// DROPDOWNS & POPUPS
|
||||
// =========================================================================
|
||||
|
||||
// 1. Apple Menu Dropdown
|
||||
AppleMenu {
|
||||
id: appleDropdown
|
||||
visible: GlobalState.appleMenuVisible
|
||||
x: 8
|
||||
y: Theme.menuBarHeight + 2
|
||||
}
|
||||
|
||||
// 2. Application Menus Dropdown (File, Edit, View, Window, Help)
|
||||
AppMenuDropdown {
|
||||
id: appMenuDropdown
|
||||
visible: GlobalState.activeDropdownMenu !== ""
|
||||
menuName: GlobalState.activeDropdownMenu
|
||||
x: 60
|
||||
y: Theme.menuBarHeight + 2
|
||||
}
|
||||
|
||||
// 3. Volume Popup
|
||||
VolumePopup {
|
||||
id: volumeDropdown
|
||||
visible: GlobalState.volumePopupVisible
|
||||
anchors.top: barRect.bottom
|
||||
anchors.topMargin: 2
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 190
|
||||
}
|
||||
|
||||
// 4. Wi-Fi Popup
|
||||
WifiPopup {
|
||||
id: wifiDropdown
|
||||
visible: GlobalState.wifiPopupVisible
|
||||
anchors.top: barRect.bottom
|
||||
anchors.topMargin: 2
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 160
|
||||
}
|
||||
|
||||
// 5. Battery Popup
|
||||
BatteryPopup {
|
||||
id: batteryDropdown
|
||||
visible: GlobalState.batteryPopupVisible
|
||||
anchors.top: barRect.bottom
|
||||
anchors.topMargin: 2
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 110
|
||||
}
|
||||
|
||||
// 6. Calendar Popup
|
||||
CalendarPopup {
|
||||
id: calDropdown
|
||||
visible: GlobalState.calendarPopupVisible
|
||||
anchors.top: barRect.bottom
|
||||
anchors.topMargin: 2
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 10
|
||||
}
|
||||
}
|
||||
340
home/hypr/quickshell/components/Spotlight.qml
Normal file
340
home/hypr/quickshell/components/Spotlight.qml
Normal file
@@ -0,0 +1,340 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Io
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: spotWindow
|
||||
visible: GlobalState.spotlightVisible
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
color: Qt.rgba(0, 0, 0, 0.35)
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.namespace: "quickshell-spotlight"
|
||||
WlrLayershell.keyboardFocus: visible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
|
||||
// Dismiss when clicking outside modal
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: GlobalState.spotlightVisible = false
|
||||
}
|
||||
|
||||
// App Database Loader Process
|
||||
readonly property Process appScanProc: Process {
|
||||
command: ["bash", "-c", "dirs=(\"/run/current-system/sw/share/applications\" \"$HOME/.nix-profile/share/applications\" \"$HOME/.local/share/applications\"); echo '['; first=1; for d in \"${dirs[@]}\"; do [ -d \"$d\" ] && for f in \"$d\"/*.desktop; do [ -e \"$f\" ] || continue; grep -q \"^NoDisplay=true\" \"$f\" 2>/dev/null && continue; n=$(grep -m 1 \"^Name=\" \"$f\" 2>/dev/null | cut -d= -f2-); e=$(grep -m 1 \"^Exec=\" \"$f\" 2>/dev/null | cut -d= -f2- | sed -E 's/%[fFuUdDnNickvm]//g'); if [ -n \"$n\" ] && [ -n \"$e\" ]; then [ $first -eq 0 ] && echo ','; first=0; echo \"{\\\"name\\\":\\\"$n\\\",\\\"exec\\\":\\\"$e\\\"}\"; fi; done; done; echo ']'"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
try {
|
||||
const parsed = JSON.parse(data.trim());
|
||||
if (Array.isArray(parsed)) {
|
||||
spotWindow.allApps = parsed;
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property var allApps: [
|
||||
{ name: "Brave Browser", exec: "brave", comment: "Web Browser", icon: "browser" },
|
||||
{ name: "Foot Terminal", exec: "foot", comment: "Terminal Emulator", icon: "terminal" },
|
||||
{ name: "Neovim", exec: "foot -e nvim", comment: "Code Editor", icon: "code" },
|
||||
{ name: "Activity Monitor (Btop)", exec: "foot -e btop", comment: "System Resources", icon: "preferences" },
|
||||
{ name: "Volume & Sound (Pavucontrol)", exec: "pavucontrol", comment: "Audio Settings", icon: "preferences" },
|
||||
{ name: "Lock Screen", exec: "hyprlock", comment: "Lock Session", icon: "preferences" },
|
||||
{ name: "System Reboot", exec: "systemctl reboot", comment: "Reboot NixOS", icon: "preferences" },
|
||||
{ name: "Shut Down", exec: "systemctl poweroff", comment: "Power Off", icon: "preferences" }
|
||||
]
|
||||
|
||||
property int selectedIndex: 0
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
appScanProc.running = true;
|
||||
searchInput.text = "";
|
||||
selectedIndex = 0;
|
||||
searchInput.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
// Centered Spotlight Search Modal
|
||||
Rectangle {
|
||||
id: modalBox
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: 140
|
||||
width: 640
|
||||
implicitHeight: searchBarRow.height + (resultsListView.count > 0 || mathResultText !== "" ? 340 : 0)
|
||||
radius: Theme.radiusModal
|
||||
color: Theme.windowBg
|
||||
border.color: Theme.windowBorder
|
||||
border.width: 1
|
||||
|
||||
Behavior on implicitHeight {
|
||||
NumberAnimation { duration: 180; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
// Prevent clicking inside from closing modal
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 14
|
||||
spacing: 12
|
||||
|
||||
// Top Search Bar
|
||||
RowLayout {
|
||||
id: searchBarRow
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 44
|
||||
spacing: 12
|
||||
|
||||
Image {
|
||||
width: 24
|
||||
height: 24
|
||||
source: "../assets/spotlight.svg"
|
||||
sourceSize: Qt.size(24, 24)
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: searchInput
|
||||
Layout.fillWidth: true
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSpotlight
|
||||
font.weight: Font.Light
|
||||
color: Theme.textPrimary
|
||||
focus: true
|
||||
clip: true
|
||||
|
||||
Text {
|
||||
anchors.fill: parent
|
||||
visible: searchInput.text === ""
|
||||
text: "Spotlight Search"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSpotlight
|
||||
font.weight: Font.Light
|
||||
color: Theme.textTertiary
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: GlobalState.spotlightVisible = false
|
||||
Keys.onDownPressed: {
|
||||
if (resultsListView.count > 0) {
|
||||
spotWindow.selectedIndex = Math.min(resultsListView.count - 1, spotWindow.selectedIndex + 1);
|
||||
}
|
||||
}
|
||||
Keys.onUpPressed: {
|
||||
if (resultsListView.count > 0) {
|
||||
spotWindow.selectedIndex = Math.max(0, spotWindow.selectedIndex - 1);
|
||||
}
|
||||
}
|
||||
Keys.onReturnPressed: {
|
||||
if (filteredModel.count > 0 && spotWindow.selectedIndex < filteredModel.count) {
|
||||
const item = filteredModel.get(spotWindow.selectedIndex);
|
||||
GlobalState.launchApp(item.exec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear button
|
||||
Rectangle {
|
||||
visible: searchInput.text !== ""
|
||||
width: 20
|
||||
height: 20
|
||||
radius: 10
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.2)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "✕"
|
||||
font.pixelSize: 11
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: searchInput.text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Math Calculation Result Banner (if valid formula)
|
||||
Rectangle {
|
||||
visible: mathResultText !== ""
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 36
|
||||
radius: Theme.radiusSmall
|
||||
color: Qt.rgba(0.04, 0.52, 1.0, 0.2)
|
||||
border.color: Theme.accentBlue
|
||||
border.width: 1
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
text: "="
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Bold
|
||||
color: Theme.accentBlue
|
||||
}
|
||||
Text {
|
||||
text: mathResultText
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.DemiBold
|
||||
color: "#FFFFFF"
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Divider Line
|
||||
Rectangle {
|
||||
visible: resultsListView.count > 0
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
}
|
||||
|
||||
// Search Results List View
|
||||
ListView {
|
||||
id: resultsListView
|
||||
visible: count > 0
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Math.min(270, count * 42)
|
||||
clip: true
|
||||
spacing: 2
|
||||
model: filteredModel
|
||||
|
||||
delegate: Rectangle {
|
||||
id: itemDelegate
|
||||
required property int index
|
||||
required property string name
|
||||
required property string exec
|
||||
required property string comment
|
||||
|
||||
width: resultsListView.width
|
||||
height: 40
|
||||
radius: Theme.radiusSmall
|
||||
color: spotWindow.selectedIndex === index ? Theme.menuHoverBlue : "transparent"
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 10
|
||||
spacing: 10
|
||||
|
||||
Image {
|
||||
width: 22
|
||||
height: 22
|
||||
source: "../assets/terminal.svg"
|
||||
sourceSize: Qt.size(22, 22)
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 1
|
||||
|
||||
Text {
|
||||
text: itemDelegate.name
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeNormal
|
||||
font.weight: Font.Medium
|
||||
color: "#FFFFFF"
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Text {
|
||||
text: itemDelegate.comment || itemDelegate.exec
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: spotWindow.selectedIndex === itemDelegate.index
|
||||
? Qt.rgba(1,1,1,0.85) : Theme.textTertiary
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "↩"
|
||||
font.pixelSize: 14
|
||||
color: spotWindow.selectedIndex === itemDelegate.index
|
||||
? "#FFFFFF" : "transparent"
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: spotWindow.selectedIndex = itemDelegate.index
|
||||
onClicked: GlobalState.launchApp(itemDelegate.exec)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Math calculation evaluator property
|
||||
readonly property string mathResultText: {
|
||||
const query = searchInput.text.trim();
|
||||
if (/^[0-9+\-*/^().\s%]+$/.test(query) && /[0-9]/.test(query) && /[+\-*/^%]/.test(query)) {
|
||||
try {
|
||||
// Safe evaluation of arithmetic
|
||||
const res = Function(`"use strict"; return (${query.replace(/\^/g, "**")})`)();
|
||||
if (typeof res === "number" && !isNaN(res) && isFinite(res)) {
|
||||
return `${res}`;
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// Filtered ListModel updated on text change
|
||||
ListModel {
|
||||
id: filteredModel
|
||||
}
|
||||
|
||||
function updateFilter() {
|
||||
filteredModel.clear();
|
||||
const query = searchInput.text.toLowerCase().trim();
|
||||
let count = 0;
|
||||
for (let i = 0; i < allApps.length && count < 12; i++) {
|
||||
const app = allApps[i];
|
||||
if (!app.name) continue;
|
||||
if (query === "" || app.name.toLowerCase().includes(query) || (app.exec && app.exec.toLowerCase().includes(query))) {
|
||||
filteredModel.append({
|
||||
name: app.name,
|
||||
exec: app.exec || "",
|
||||
comment: app.comment || ""
|
||||
});
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: searchInput
|
||||
function onTextChanged() {
|
||||
spotWindow.selectedIndex = 0;
|
||||
updateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: updateFilter()
|
||||
}
|
||||
148
home/hypr/quickshell/components/VolumePopup.qml
Normal file
148
home/hypr/quickshell/components/VolumePopup.qml
Normal file
@@ -0,0 +1,148 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
width: 240
|
||||
height: 110
|
||||
radius: Theme.radiusMedium
|
||||
color: Theme.menuDropdownBg
|
||||
border.color: Theme.menuDropdownBorder
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 8
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
text: "Sound"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeNormal
|
||||
font.weight: Font.DemiBold
|
||||
color: Theme.textPrimary
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Text {
|
||||
text: `${GlobalState.volume}%`
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textSecondary
|
||||
}
|
||||
}
|
||||
|
||||
// Custom Catalina Volume Slider
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 24
|
||||
|
||||
Rectangle {
|
||||
id: track
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: 6
|
||||
radius: 3
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.2)
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: track.width * (GlobalState.volume / 100.0)
|
||||
radius: 3
|
||||
color: Theme.accentBlue
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: thumb
|
||||
x: Math.max(0, Math.min(track.width - width, (track.width * (GlobalState.volume / 100.0)) - width / 2))
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 16
|
||||
height: 16
|
||||
radius: 8
|
||||
color: "#FFFFFF"
|
||||
border.color: Qt.rgba(0, 0, 0, 0.2)
|
||||
border.width: 1
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
preventStealing: true
|
||||
|
||||
function updateFromMouse(mouse) {
|
||||
const frac = Math.max(0.0, Math.min(1.0, mouse.x / width));
|
||||
GlobalState.setVolume(Math.round(frac * 100));
|
||||
}
|
||||
|
||||
onPressed: (mouse) => updateFromMouse(mouse)
|
||||
onPositionChanged: (mouse) => {
|
||||
if (pressed) updateFromMouse(mouse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom Controls
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 24
|
||||
radius: Theme.radiusSmall
|
||||
color: muteMouse.containsMouse ? Qt.rgba(1.0, 1.0, 1.0, 0.15) : Qt.rgba(1.0, 1.0, 1.0, 0.08)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: GlobalState.volumeMuted ? "Unmute" : "Mute"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: muteMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: GlobalState.toggleVolumeMute()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 24
|
||||
radius: Theme.radiusSmall
|
||||
color: prefMouse.containsMouse ? Qt.rgba(1.0, 1.0, 1.0, 0.15) : Qt.rgba(1.0, 1.0, 1.0, 0.08)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "Sound Preferences..."
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: prefMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
GlobalState.volumePopupVisible = false;
|
||||
GlobalState.launchApp("pavucontrol");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
home/hypr/quickshell/components/WifiPopup.qml
Normal file
102
home/hypr/quickshell/components/WifiPopup.qml
Normal file
@@ -0,0 +1,102 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
width: 240
|
||||
implicitHeight: wifiCol.implicitHeight + 24
|
||||
radius: Theme.radiusMedium
|
||||
color: Theme.menuDropdownBg
|
||||
border.color: Theme.menuDropdownBorder
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
id: wifiCol
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 8
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
text: "Wi-Fi"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeNormal
|
||||
font.weight: Font.DemiBold
|
||||
color: Theme.textPrimary
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.wifiConnected ? "On" : "Off"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: GlobalState.wifiConnected ? Theme.accentGreen : Theme.textTertiary
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
}
|
||||
|
||||
// Active network info
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 3
|
||||
|
||||
Text {
|
||||
text: GlobalState.wifiConnected ? `Connected to: ${GlobalState.wifiSsid}` : "No Network Connected"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.textPrimary
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Text {
|
||||
visible: GlobalState.ipAddress !== "" && GlobalState.ipAddress !== "Offline"
|
||||
text: `IP: ${GlobalState.ipAddress}`
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textSecondary
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 24
|
||||
radius: Theme.radiusSmall
|
||||
color: netMouse.containsMouse ? Qt.rgba(1.0, 1.0, 1.0, 0.15) : Qt.rgba(1.0, 1.0, 1.0, 0.08)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "Network Preferences..."
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: netMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
GlobalState.wifiPopupVisible = false;
|
||||
GlobalState.launchApp("nm-connection-editor || foot -e nmtui");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user