updated pi, quickshell, and ollama
This commit is contained in:
@@ -47,6 +47,20 @@ QtObject {
|
||||
property bool batteryCharging: false
|
||||
property string batteryStatus: "Full"
|
||||
|
||||
// GPU VRAM Monitoring (NVIDIA)
|
||||
property string gpuVramUsed: "0"
|
||||
property string gpuVramTotal: "0"
|
||||
property int gpuVramPercent: 0
|
||||
|
||||
// System HUD state (replaces individual popup states)
|
||||
property bool systemHudVisible: false
|
||||
property string systemHudActiveSection: "" // "volume", "wifi", "calendar", etc.
|
||||
|
||||
// Workspace tracking
|
||||
property int activeWorkspace: 1
|
||||
property var workspaceList: [1, 2, 3, 4, 5]
|
||||
property var workspaceNames: ({1: "main", 2: "browser", 3: "code", 4: "media", 5: "misc"})
|
||||
|
||||
// Media Player State (MPRIS)
|
||||
property string mediaTitle: ""
|
||||
property string mediaArtist: ""
|
||||
@@ -60,6 +74,7 @@ QtObject {
|
||||
wifiPopupVisible = false;
|
||||
batteryPopupVisible = false;
|
||||
calendarPopupVisible = false;
|
||||
systemHudVisible = false;
|
||||
}
|
||||
|
||||
function toggleSpotlight() {
|
||||
@@ -77,12 +92,25 @@ QtObject {
|
||||
aboutMacVisible = !aboutMacVisible;
|
||||
}
|
||||
|
||||
function toggleSystemHud() {
|
||||
closeAllPopups();
|
||||
systemHudVisible = !systemHudVisible;
|
||||
}
|
||||
|
||||
function switchWorkspace(n) {
|
||||
Hyprland.dispatch("workspace " + n);
|
||||
}
|
||||
|
||||
// Hyprland raw event processing
|
||||
readonly property Connections hyprConn: Connections {
|
||||
target: Hyprland
|
||||
function onRawEvent(event) {
|
||||
function onRawEvent(event) { console.log(JSON.stringify(event), event.name, event.event, event.data);
|
||||
if (!event) return;
|
||||
if (event.startsWith("activewindow>>")) {
|
||||
if (event.startsWith("workspace>>")) {
|
||||
const data = event.substring(11);
|
||||
const wsNum = parseInt(data);
|
||||
if (!isNaN(wsNum)) root.activeWorkspace = wsNum;
|
||||
} else if (event.startsWith("activewindow>>")) {
|
||||
const data = event.substring(14);
|
||||
const parts = data.split(",");
|
||||
const title = parts[1] ? parts[1].trim() : (parts[0] ? parts[0].trim() : "");
|
||||
@@ -127,6 +155,7 @@ QtObject {
|
||||
audioProc.running = true;
|
||||
brightProc.running = true;
|
||||
mprisProc.running = true;
|
||||
gpuProc.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +164,7 @@ QtObject {
|
||||
command: ["bash", "-c", "read -r c u n s i io ir st g gn < /proc/stat; t1=$((u+n+s+i+io+ir+st+g+gn)); i1=$((i+io)); sleep 0.15; read -r c u n s i io ir st g gn < /proc/stat; t2=$((u+n+s+i+io+ir+st+g+gn)); i2=$((i+io)); td=$((t2-t1)); id=$((i2-i1)); [ $td -gt 0 ] && echo $(( (td-id)*100/td )) || echo 0"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const val = parseInt(data.trim());
|
||||
const val = parseInt(String(data).trim());
|
||||
if (!isNaN(val)) root.cpuPercent = Math.max(0, Math.min(100, val));
|
||||
}
|
||||
}
|
||||
@@ -145,7 +174,7 @@ QtObject {
|
||||
command: ["bash", "-c", "t=$(grep MemTotal /proc/meminfo | awk '{print $2}'); a=$(grep MemAvailable /proc/meminfo | awk '{print $2}'); if [ -n \"$t\" ] && [ -n \"$a\" ] && [ \"$t\" -gt 0 ]; then u=$((t-a)); p=$((u*100/t)); ug=$(awk \"BEGIN {printf \\\"%.1f\\\", $u/1048576}\"); tg=$(awk \"BEGIN {printf \\\"%.1f\\\", $t/1048576}\"); echo \"$p $ug $tg\"; fi"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const parts = data.trim().split(" ");
|
||||
const parts = String(data).trim().split(" ");
|
||||
if (parts.length >= 3) {
|
||||
root.memPercent = parseInt(parts[0]) || 0;
|
||||
root.memUsedGb = parts[1];
|
||||
@@ -159,7 +188,7 @@ QtObject {
|
||||
command: ["bash", "-c", "b=$(find /sys/class/power_supply/ -name 'BAT*' 2>/dev/null | head -n 1); if [ -n \"$b\" ]; then cap=$(cat $b/capacity 2>/dev/null || echo 100); st=$(cat $b/status 2>/dev/null || echo Full); echo \"1 $cap $st\"; else echo \"0 100 AC\"; fi"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const parts = data.trim().split(" ");
|
||||
const parts = String(data).trim().split(" ");
|
||||
if (parts.length >= 3) {
|
||||
root.batteryPresent = parts[0] === "1";
|
||||
root.batteryPercent = parseInt(parts[1]) || 100;
|
||||
@@ -174,7 +203,7 @@ QtObject {
|
||||
command: ["bash", "-c", "ssid=\"\"; if command -v nmcli &>/dev/null; then ssid=$(nmcli -t -f active,ssid dev wifi 2>/dev/null | grep '^yes:' | cut -d':' -f2); fi; [ -z \"$ssid\" ] && [ -f /proc/net/wireless ] && ssid=$(iwgetid -r 2>/dev/null); ip=$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{print $7; exit}'); echo \"${ssid:-Ethernet} ${ip:-Offline}\""]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const str = data.trim();
|
||||
const str = String(data).trim();
|
||||
const parts = str.split(" ");
|
||||
if (parts.length >= 2) {
|
||||
root.wifiSsid = parts[0];
|
||||
@@ -189,7 +218,7 @@ QtObject {
|
||||
command: ["bash", "-c", "if command -v pactl &>/dev/null; then v=$(pactl get-sink-volume @DEFAULT_SINK@ 2>/dev/null | grep -Po '[0-9]+(?=%)' | head -n 1); m=$(pactl get-sink-mute @DEFAULT_SINK@ 2>/dev/null | grep -q yes && echo 1 || echo 0); echo \"${v:-50} $m\"; fi"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const parts = data.trim().split(" ");
|
||||
const parts = String(data).trim().split(" ");
|
||||
if (parts.length >= 2) {
|
||||
root.volume = parseInt(parts[0]) || 50;
|
||||
root.volumeMuted = parts[1] === "1";
|
||||
@@ -202,7 +231,7 @@ QtObject {
|
||||
command: ["bash", "-c", "if command -v brightnessctl &>/dev/null; then b=$(brightnessctl -m 2>/dev/null | cut -d, -f4 | tr -d '%'); echo \"${b:-100}\"; else echo 100; fi"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const val = parseInt(data.trim());
|
||||
const val = parseInt(String(data).trim());
|
||||
if (!isNaN(val)) root.brightness = val;
|
||||
}
|
||||
}
|
||||
@@ -212,7 +241,7 @@ QtObject {
|
||||
command: ["bash", "-c", "if command -v playerctl &>/dev/null; then t=$(playerctl metadata title 2>/dev/null); a=$(playerctl metadata artist 2>/dev/null); s=$(playerctl status 2>/dev/null); echo \"$s|$t|$a\"; fi"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const parts = data.trim().split("|");
|
||||
const parts = String(data).trim().split("|");
|
||||
if (parts.length >= 3) {
|
||||
root.mediaPlaying = parts[0] === "Playing";
|
||||
root.mediaTitle = parts[1] || "";
|
||||
@@ -226,12 +255,30 @@ QtObject {
|
||||
}
|
||||
}
|
||||
|
||||
readonly property Process gpuProc: Process {
|
||||
command: ["bash", "-c", "nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader,nounits 2>/dev/null || echo '0, 0'"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const parts = String(data).trim().split(",");
|
||||
if (parts.length >= 2) {
|
||||
const usedMiB = parseInt(parts[0].trim());
|
||||
const totalMiB = parseInt(parts[1].trim());
|
||||
if (!isNaN(usedMiB) && !isNaN(totalMiB) && totalMiB > 0) {
|
||||
root.gpuVramUsed = (usedMiB / 1024).toFixed(1);
|
||||
root.gpuVramTotal = (totalMiB / 1024).toFixed(1);
|
||||
root.gpuVramPercent = Math.round((usedMiB / totalMiB) * 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly property Process clientsProc: Process {
|
||||
command: ["bash", "-c", "if command -v hyprctl &>/dev/null; then hyprctl -j clients 2>/dev/null; else echo '[]'; fi"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
try {
|
||||
const parsed = JSON.parse(data.trim());
|
||||
const parsed = JSON.parse(String(data).trim());
|
||||
if (Array.isArray(parsed)) {
|
||||
root.runningApps = parsed;
|
||||
}
|
||||
|
||||
190
home/hypr/quickshell/components/QuickMenu.qml
Normal file
190
home/hypr/quickshell/components/QuickMenu.qml
Normal file
@@ -0,0 +1,190 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Io
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: quickMenu
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
}
|
||||
|
||||
margins {
|
||||
top: 0
|
||||
left: Theme.sidebarWidth
|
||||
}
|
||||
|
||||
visible: GlobalState.appleMenuVisible
|
||||
|
||||
implicitWidth: 220
|
||||
implicitHeight: menuContainer.implicitHeight
|
||||
|
||||
color: "transparent"
|
||||
|
||||
// Close on escape
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
Keys.onEscapePressed: GlobalState.appleMenuVisible = false
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: menuContainer
|
||||
anchors.fill: parent
|
||||
color: Theme.glassBg
|
||||
border.color: Theme.glassBorder
|
||||
border.width: 1
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
padding: 8
|
||||
|
||||
component MenuItem: Item {
|
||||
id: menuItem
|
||||
width: parent.width
|
||||
height: 28
|
||||
|
||||
property string text: ""
|
||||
property string shortcut: ""
|
||||
signal triggered()
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: menuItemMouseArea.containsMouse ? Qt.rgba(Theme.accentVolt.r, Theme.accentVolt.g, Theme.accentVolt.b, 0.1) : "transparent"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: Theme.accentVolt
|
||||
visible: menuItemMouseArea.containsMouse
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 12
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: menuItem.text
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
color: menuItemMouseArea.containsMouse ? Theme.textPrimary : Theme.textSecondary
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: menuItem.shortcut
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 11
|
||||
color: Theme.textMuted
|
||||
visible: text !== ""
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: menuItemMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
menuItem.triggered()
|
||||
GlobalState.appleMenuVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component MenuSeparator: Item {
|
||||
width: parent.width
|
||||
height: 17
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 12
|
||||
anchors.rightMargin: 12
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "System Info..."
|
||||
onTriggered: GlobalState.aboutMacVisible = true
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "System Preferences..."
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["pavucontrol"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Activity Monitor"
|
||||
shortcut: "btop"
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["foot", "-e", "btop"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
MenuItem {
|
||||
text: "Sleep"
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["systemctl", "suspend"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Restart..."
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["systemctl", "reboot"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Shut Down..."
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["systemctl", "poweroff"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
MenuItem {
|
||||
text: "Lock Screen"
|
||||
shortcut: "Super+L"
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["hyprlock"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Log Out"
|
||||
shortcut: "Super+Shift+Q"
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["hyprctl", "dispatch", "exit"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
531
home/hypr/quickshell/components/SidePanel.qml
Normal file
531
home/hypr/quickshell/components/SidePanel.qml
Normal file
@@ -0,0 +1,531 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Wayland
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
property var screen
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
WlrLayershell.namespace: "quickshell-sidepanel"
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
bottom: true
|
||||
left: true
|
||||
right: false
|
||||
}
|
||||
|
||||
exclusiveZone: Theme.sidebarWidth
|
||||
implicitWidth: Theme.sidebarWidth
|
||||
color: Theme.bgPrimary
|
||||
|
||||
// Right edge hairline border
|
||||
Rectangle {
|
||||
width: 1
|
||||
color: Theme.glassBorder
|
||||
anchors {
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
|
||||
component Separator: Rectangle {
|
||||
width: 36
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
component DockIcon: Item {
|
||||
id: dockIconRoot
|
||||
width: 36
|
||||
height: 36
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
property string appClass: ""
|
||||
property string execCmd: ""
|
||||
property string iconSource: ""
|
||||
property string tooltipText: ""
|
||||
|
||||
property bool isRunning: (appClass !== "" && GlobalState.activeWindowClass === appClass) || (GlobalState.runningApps && GlobalState.runningApps.indexOf(appClass) !== -1)
|
||||
|
||||
Image {
|
||||
id: img
|
||||
anchors.centerIn: parent
|
||||
width: 24
|
||||
height: 24
|
||||
source: iconSource ? Qt.resolvedUrl("../assets/" + iconSource) : ""
|
||||
sourceSize: Qt.size(24, 24)
|
||||
fillMode: Image.PreserveAspectFit
|
||||
opacity: mouseArea.containsMouse ? 1.0 : 0.8
|
||||
|
||||
scale: mouseArea.containsMouse ? 1.15 : 1.0
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: runningDot
|
||||
width: 4
|
||||
height: 4
|
||||
radius: 2
|
||||
color: Theme.accentVolt
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: isRunning
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
if (execCmd !== "") {
|
||||
GlobalState.launchApp(execCmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tooltip
|
||||
Rectangle {
|
||||
id: tooltip
|
||||
visible: mouseArea.containsMouse && tooltipText !== ""
|
||||
color: Theme.glassBg
|
||||
radius: 4
|
||||
width: tooltipLabel.implicitWidth + 16
|
||||
height: tooltipLabel.implicitHeight + 8
|
||||
|
||||
anchors.left: parent.right
|
||||
anchors.leftMargin: 24
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Text {
|
||||
id: tooltipLabel
|
||||
anchors.centerIn: parent
|
||||
text: tooltipText
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 11
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
|
||||
// Top spacer
|
||||
Item { height: 4; Layout.fillWidth: true }
|
||||
|
||||
// 1. AG Logo Button
|
||||
Rectangle {
|
||||
width: 36
|
||||
height: 36
|
||||
radius: 4
|
||||
color: logoMouse.containsMouse ? Qt.rgba(1,1,1,0.05) : "transparent"
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "AG"
|
||||
font.family: Theme.fontSerif
|
||||
font.italic: true
|
||||
font.pixelSize: 16
|
||||
color: Theme.accentVolt
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: logoMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: GlobalState.appleMenuVisible = !GlobalState.appleMenuVisible
|
||||
}
|
||||
}
|
||||
|
||||
Separator {}
|
||||
|
||||
// 3. Workspace Indicators
|
||||
Column {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 2
|
||||
|
||||
Repeater {
|
||||
model: GlobalState.workspaceList
|
||||
delegate: Rectangle {
|
||||
width: 52
|
||||
height: 36
|
||||
color: wsMouse.containsMouse ? Qt.rgba(1,1,1,0.04) : "transparent"
|
||||
|
||||
property bool isActive: GlobalState.activeWorkspace === modelData
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 2
|
||||
height: 20
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: Theme.accentVolt
|
||||
visible: isActive
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: (modelData < 10 ? "0" : "") + modelData
|
||||
color: isActive ? Theme.accentVolt : Theme.textMuted
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: (GlobalState.workspaceNames && GlobalState.workspaceNames[modelData]) ? GlobalState.workspaceNames[modelData] : ""
|
||||
color: Theme.textMuted
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 8
|
||||
opacity: 0.7
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: wsMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: GlobalState.switchWorkspace(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Separator {}
|
||||
|
||||
// 5. Spotlight trigger
|
||||
Item {
|
||||
width: 36
|
||||
height: 36
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "⌕"
|
||||
font.pixelSize: 20
|
||||
color: spotlightMouse.containsMouse ? Theme.accentVolt : Theme.textMuted
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: spotlightMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: GlobalState.toggleSpotlight()
|
||||
}
|
||||
}
|
||||
|
||||
Separator {}
|
||||
|
||||
// 7. Pinned Apps
|
||||
Column {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 8
|
||||
|
||||
DockIcon {
|
||||
appClass: ""
|
||||
execCmd: "nautilus"
|
||||
iconSource: "finder.svg"
|
||||
tooltipText: "Finder"
|
||||
}
|
||||
DockIcon {
|
||||
appClass: "brave-browser"
|
||||
execCmd: "brave"
|
||||
iconSource: "browser.svg"
|
||||
tooltipText: "Brave Browser"
|
||||
}
|
||||
DockIcon {
|
||||
appClass: "foot"
|
||||
execCmd: "foot"
|
||||
iconSource: "terminal.svg"
|
||||
tooltipText: "Terminal"
|
||||
}
|
||||
DockIcon {
|
||||
appClass: "nvim"
|
||||
execCmd: "foot -e nvim"
|
||||
iconSource: "code.svg"
|
||||
tooltipText: "Code"
|
||||
}
|
||||
DockIcon {
|
||||
appClass: "pavucontrol"
|
||||
execCmd: "pavucontrol"
|
||||
iconSource: "preferences.svg"
|
||||
tooltipText: "Settings"
|
||||
}
|
||||
DockIcon {
|
||||
appClass: ""
|
||||
execCmd: "spotify"
|
||||
iconSource: "music.svg"
|
||||
tooltipText: "Music"
|
||||
}
|
||||
}
|
||||
|
||||
Separator {}
|
||||
|
||||
// 9. Running Apps (non-pinned)
|
||||
Column {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 8
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
var pinned = ["foot", "brave-browser", "pavucontrol", "nvim", "nautilus", "spotify", ""]
|
||||
var running = []
|
||||
var seen = {}
|
||||
if (GlobalState.runningApps) {
|
||||
for (var i = 0; i < GlobalState.runningApps.length; i++) {
|
||||
var cls = GlobalState.runningApps[i]
|
||||
if (cls && pinned.indexOf(cls) === -1 && !seen[cls]) {
|
||||
seen[cls] = true
|
||||
running.push(cls)
|
||||
}
|
||||
}
|
||||
}
|
||||
return running
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
width: 36
|
||||
height: 36
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 12
|
||||
color: Qt.rgba(1, 1, 1, 0.1)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: modelData.charAt(0).toUpperCase()
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 12
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 4
|
||||
height: 4
|
||||
radius: 2
|
||||
color: Theme.accentVolt
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
// Focus app logic here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 10. Flexible spacer
|
||||
Item { Layout.fillHeight: true }
|
||||
|
||||
Separator {}
|
||||
|
||||
// 12. Telemetry mini-readouts
|
||||
Column {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "CPU" + (GlobalState.cpuPercent !== undefined ? GlobalState.cpuPercent : "0") + "%"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 11
|
||||
color: (GlobalState.cpuPercent !== undefined && GlobalState.cpuPercent > 80) ? Theme.accentCoral : Theme.textMuted
|
||||
Behavior on color { ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
||||
}
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "RAM" + (GlobalState.memUsedGb !== undefined ? GlobalState.memUsedGb : "0") + "G"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 11
|
||||
color: (GlobalState.memPercent !== undefined && GlobalState.memPercent > 85) ? Theme.accentCoral : Theme.textMuted
|
||||
Behavior on color { ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
||||
}
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "VRM" + (GlobalState.gpuVramUsed !== undefined ? GlobalState.gpuVramUsed : "0") + "G"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 11
|
||||
color: Theme.textMuted
|
||||
}
|
||||
}
|
||||
|
||||
Separator {}
|
||||
|
||||
// 14. System tray icons
|
||||
Column {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 8
|
||||
|
||||
// Volume
|
||||
Item {
|
||||
width: 36
|
||||
height: 36
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 16
|
||||
height: 16
|
||||
source: Qt.resolvedUrl("../assets/volume.svg")
|
||||
sourceSize: Qt.size(16, 16)
|
||||
opacity: volMouse.containsMouse ? 1.0 : 0.7
|
||||
Behavior on opacity { NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
||||
}
|
||||
MouseArea {
|
||||
id: volMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
GlobalState.systemHudActiveSection = "volume"
|
||||
GlobalState.systemHudVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WiFi
|
||||
Item {
|
||||
width: 36
|
||||
height: 36
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 16
|
||||
height: 16
|
||||
source: Qt.resolvedUrl("../assets/wifi.svg")
|
||||
sourceSize: Qt.size(16, 16)
|
||||
opacity: GlobalState.wifiConnected ? 0.7 : 0.3
|
||||
Behavior on opacity { NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
GlobalState.systemHudActiveSection = "network"
|
||||
GlobalState.systemHudVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Battery
|
||||
Item {
|
||||
width: 36
|
||||
height: 44
|
||||
visible: GlobalState.batteryPresent !== undefined ? GlobalState.batteryPresent : false
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 2
|
||||
|
||||
Image {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 16
|
||||
height: 16
|
||||
source: Qt.resolvedUrl("../assets/battery.svg")
|
||||
sourceSize: Qt.size(16, 16)
|
||||
opacity: (GlobalState.batteryPercent !== undefined && GlobalState.batteryPercent < 20) ? 1.0 : 0.7
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: (GlobalState.batteryPercent !== undefined ? GlobalState.batteryPercent : "100") + "%"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 9
|
||||
color: (GlobalState.batteryPercent !== undefined && GlobalState.batteryPercent < 20) ? Theme.accentCoral : Theme.textSecondary
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
GlobalState.systemHudActiveSection = "battery"
|
||||
GlobalState.systemHudVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Separator {}
|
||||
|
||||
// 16. Clock
|
||||
Item {
|
||||
width: 36
|
||||
height: 44
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: GlobalState.timeString !== undefined ? GlobalState.timeString : "00:00"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: GlobalState.dateString !== undefined ? GlobalState.dateString : "Jan 01"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 9
|
||||
color: Theme.textMuted
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
GlobalState.systemHudActiveSection = "calendar"
|
||||
GlobalState.systemHudVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom spacer
|
||||
Item { height: 4; Layout.fillWidth: true }
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ PanelWindow {
|
||||
bottom: true
|
||||
}
|
||||
|
||||
color: Qt.rgba(0, 0, 0, 0.35)
|
||||
color: Qt.rgba(0, 0, 0, 0.45)
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.namespace: "quickshell-spotlight"
|
||||
WlrLayershell.keyboardFocus: visible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
@@ -35,7 +35,7 @@ PanelWindow {
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
try {
|
||||
const parsed = JSON.parse(data.trim());
|
||||
const parsed = JSON.parse(String(data).trim());
|
||||
if (Array.isArray(parsed)) {
|
||||
spotWindow.allApps = parsed;
|
||||
}
|
||||
@@ -67,223 +67,246 @@ PanelWindow {
|
||||
}
|
||||
|
||||
// Centered Spotlight Search Modal
|
||||
Rectangle {
|
||||
id: modalBox
|
||||
Item {
|
||||
id: modalContainer
|
||||
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
|
||||
height: modalBox.implicitHeight
|
||||
|
||||
scale: spotWindow.visible ? 1.0 : 0.96
|
||||
opacity: spotWindow.visible ? 1.0 : 0.0
|
||||
|
||||
Behavior on implicitHeight {
|
||||
NumberAnimation { duration: 180; easing.type: Easing.OutQuad }
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: Theme.animSmooth; easing.type: Easing.OutQuint }
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: Theme.animSmooth; easing.type: Easing.OutQuint }
|
||||
}
|
||||
|
||||
// Prevent clicking inside from closing modal
|
||||
MouseArea {
|
||||
Rectangle {
|
||||
id: modalBox
|
||||
anchors.fill: parent
|
||||
onClicked: {}
|
||||
}
|
||||
implicitHeight: searchBarRowContainer.height + (resultsListView.count > 0 || mathResultText !== "" ? 340 : 0)
|
||||
radius: 0
|
||||
color: Theme.bgPrimary
|
||||
border.color: Theme.glassBorder
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 14
|
||||
spacing: 12
|
||||
Behavior on implicitHeight {
|
||||
NumberAnimation { duration: 180; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
// Top Search Bar
|
||||
RowLayout {
|
||||
id: searchBarRow
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 44
|
||||
spacing: 12
|
||||
// Prevent clicking inside from closing modal
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {}
|
||||
}
|
||||
|
||||
Image {
|
||||
width: 24
|
||||
height: 24
|
||||
source: "../assets/spotlight.svg"
|
||||
sourceSize: Qt.size(24, 24)
|
||||
}
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
TextInput {
|
||||
id: searchInput
|
||||
// Top Search Bar Area
|
||||
Item {
|
||||
id: searchBarRowContainer
|
||||
Layout.fillWidth: true
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSpotlight
|
||||
font.weight: Font.Light
|
||||
color: Theme.textPrimary
|
||||
focus: true
|
||||
clip: true
|
||||
Layout.preferredHeight: 64
|
||||
|
||||
Text {
|
||||
RowLayout {
|
||||
id: searchBarRow
|
||||
anchors.fill: parent
|
||||
visible: searchInput.text === ""
|
||||
text: "Spotlight Search"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSpotlight
|
||||
font.weight: Font.Light
|
||||
color: Theme.textTertiary
|
||||
anchors.margins: 14
|
||||
spacing: 12
|
||||
|
||||
Text {
|
||||
text: "⌕"
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 24
|
||||
color: Theme.accentVolt
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: searchInput
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 20
|
||||
color: Theme.textPrimary
|
||||
focus: true
|
||||
clip: true
|
||||
|
||||
Text {
|
||||
anchors.fill: parent
|
||||
visible: searchInput.text === ""
|
||||
text: "Spotlight Search"
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 20
|
||||
color: Theme.textMuted
|
||||
}
|
||||
|
||||
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: 24
|
||||
height: 24
|
||||
radius: 0
|
||||
color: "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "✕"
|
||||
font.pixelSize: 16
|
||||
color: clearMouseArea.containsMouse ? Theme.textPrimary : Theme.textMuted
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: clearMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: searchInput.text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
}
|
||||
|
||||
// Clear button
|
||||
// Math Calculation Result Banner (if valid formula)
|
||||
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"
|
||||
visible: mathResultText !== ""
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 36
|
||||
Layout.margins: 14
|
||||
radius: 0
|
||||
color: "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
|
||||
}
|
||||
}
|
||||
anchors.margins: 8
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
text: "↩"
|
||||
font.pixelSize: 14
|
||||
color: spotWindow.selectedIndex === itemDelegate.index
|
||||
? "#FFFFFF" : "transparent"
|
||||
text: "="
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Bold
|
||||
color: Theme.accentVolt
|
||||
}
|
||||
Text {
|
||||
text: mathResultText
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 16
|
||||
color: Theme.accentVolt
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: spotWindow.selectedIndex = itemDelegate.index
|
||||
onClicked: GlobalState.launchApp(itemDelegate.exec)
|
||||
// Search Results List View
|
||||
ListView {
|
||||
id: resultsListView
|
||||
visible: count > 0
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Math.min(270, count * 40)
|
||||
Layout.topMargin: 8
|
||||
Layout.bottomMargin: 8
|
||||
clip: true
|
||||
spacing: 0
|
||||
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: 0
|
||||
color: spotWindow.selectedIndex === index ? Qt.rgba(0.812, 0.988, 0.0, 0.08) : "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: Theme.accentVolt
|
||||
visible: spotWindow.selectedIndex === index
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 14
|
||||
anchors.rightMargin: 14
|
||||
spacing: 12
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
text: itemDelegate.name
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 14
|
||||
color: Theme.textPrimary
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Text {
|
||||
text: itemDelegate.comment || itemDelegate.exec
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 11
|
||||
color: Theme.textMuted
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "↩"
|
||||
font.pixelSize: 14
|
||||
color: spotWindow.selectedIndex === itemDelegate.index
|
||||
? Theme.textPrimary : "transparent"
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: spotWindow.selectedIndex = itemDelegate.index
|
||||
onClicked: GlobalState.launchApp(itemDelegate.exec)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
685
home/hypr/quickshell/components/SystemHUD.qml
Normal file
685
home/hypr/quickshell/components/SystemHUD.qml
Normal file
@@ -0,0 +1,685 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Io
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
bottom: true
|
||||
left: true
|
||||
}
|
||||
|
||||
margins {
|
||||
left: Theme.sidebarWidth
|
||||
top: Theme.topStripHeight
|
||||
}
|
||||
|
||||
implicitWidth: Theme.hudWidth
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.namespace: "quickshell-systemhud"
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||
|
||||
visible: GlobalState.systemHudVisible
|
||||
|
||||
color: "transparent"
|
||||
|
||||
property real slideOffset: GlobalState.systemHudVisible ? 0 : -Theme.hudWidth
|
||||
Behavior on slideOffset {
|
||||
NumberAnimation {
|
||||
duration: Theme.animSmooth
|
||||
easing.type: Easing.OutQuint
|
||||
}
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: "Escape"
|
||||
onActivated: GlobalState.systemHudVisible = false
|
||||
}
|
||||
|
||||
component SectionHeader: Item {
|
||||
property string sectionNum: "00"
|
||||
property string title: "Section"
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 24
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
Text {
|
||||
text: sectionNum + " //"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
color: Theme.accentVolt
|
||||
}
|
||||
Text {
|
||||
text: title
|
||||
font.family: Theme.fontSerif
|
||||
font.italic: true
|
||||
font.pixelSize: 16
|
||||
color: Theme.textPrimary
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component ToggleCard: Rectangle {
|
||||
property string title: ""
|
||||
property string icon: ""
|
||||
property bool active: false
|
||||
signal clicked()
|
||||
|
||||
Layout.preferredWidth: 160
|
||||
Layout.preferredHeight: 56
|
||||
color: Theme.bgPrimary
|
||||
border.color: active ? Qt.rgba(Theme.accentVolt.r, Theme.accentVolt.g, Theme.accentVolt.b, 0.3) : Theme.glassBorder
|
||||
border.width: 1
|
||||
radius: 4
|
||||
|
||||
Behavior on border.color { ColorAnimation { duration: Theme.animFast } }
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: clicked()
|
||||
onEntered: if (!active) border.color = Theme.glassBorderHover
|
||||
onExited: if (!active) border.color = Theme.glassBorder
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 12
|
||||
Image {
|
||||
source: icon ? Qt.resolvedUrl("../" + icon) : ""
|
||||
Layout.preferredWidth: 24
|
||||
Layout.preferredHeight: 24
|
||||
sourceSize: Qt.size(24, 24)
|
||||
visible: parent.icon !== ""
|
||||
}
|
||||
Text {
|
||||
text: title
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component CustomSlider: Item {
|
||||
property real value: 0
|
||||
signal valueChangedUser(real newVal)
|
||||
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 24
|
||||
|
||||
Rectangle {
|
||||
id: track
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width - 40
|
||||
height: 6
|
||||
color: Theme.bgSecondary
|
||||
radius: 3
|
||||
|
||||
Rectangle {
|
||||
id: fill
|
||||
width: track.width * (parent.parent.value / 100)
|
||||
height: track.height
|
||||
color: Theme.accentVolt
|
||||
radius: 3
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 14
|
||||
height: 14
|
||||
radius: 7
|
||||
color: Theme.textPrimary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
x: Math.max(0, fill.width - 7)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -10
|
||||
function updateValue(mouseX) {
|
||||
let p = Math.max(0, Math.min(1, mouseX / track.width))
|
||||
parent.parent.valueChangedUser(p * 100)
|
||||
}
|
||||
onPressed: (mouse) => updateValue(mouse.x)
|
||||
onPositionChanged: (mouse) => updateValue(mouse.x)
|
||||
}
|
||||
}
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: Math.round(parent.value) + "%"
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
}
|
||||
}
|
||||
|
||||
component ProgressBarItem: ColumnLayout {
|
||||
property string label: ""
|
||||
property real percent: 0
|
||||
property string valueText: ""
|
||||
property color barColor: Theme.accentVolt
|
||||
|
||||
Layout.fillWidth: true
|
||||
spacing: 4
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
text: parent.parent.label
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
Text {
|
||||
text: parent.parent.valueText
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 8
|
||||
color: Theme.bgSecondary
|
||||
radius: 4
|
||||
|
||||
Rectangle {
|
||||
width: parent.width * (parent.parent.percent / 100)
|
||||
height: parent.height
|
||||
color: parent.parent.barColor
|
||||
radius: 4
|
||||
Behavior on width { NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
||||
Behavior on color { ColorAnimation { duration: Theme.animFast } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: panelContent
|
||||
anchors.fill: parent
|
||||
color: Theme.glassBg
|
||||
opacity: GlobalState.systemHudVisible ? 1 : 0
|
||||
|
||||
transform: Translate { x: slideOffset }
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.animSmooth
|
||||
easing.type: Easing.OutQuint
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
|
||||
Item {
|
||||
id: header
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 60
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 20
|
||||
anchors.rightMargin: 20
|
||||
|
||||
Text {
|
||||
text: "System HUD"
|
||||
font.family: Theme.fontSerif
|
||||
font.italic: true
|
||||
font.pixelSize: 19
|
||||
color: Theme.textPrimary
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "✕"
|
||||
color: Theme.textMuted
|
||||
font.pixelSize: 16
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -10
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = Theme.textPrimary
|
||||
onExited: parent.color = Theme.textMuted
|
||||
onClicked: GlobalState.systemHudVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
id: scrollView
|
||||
anchors.top: header.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
contentWidth: availableWidth
|
||||
clip: true
|
||||
|
||||
ColumnLayout {
|
||||
id: contentLayout
|
||||
width: parent.width - 40
|
||||
x: 20
|
||||
spacing: 32
|
||||
|
||||
Item { Layout.preferredHeight: 16 } // Top padding
|
||||
|
||||
// Section 1: Toggles
|
||||
ColumnLayout {
|
||||
id: sectionToggles
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
SectionHeader { sectionNum: "01"; title: "Toggles" }
|
||||
GridLayout {
|
||||
columns: 2
|
||||
columnSpacing: 12
|
||||
rowSpacing: 12
|
||||
Layout.fillWidth: true
|
||||
|
||||
ToggleCard {
|
||||
title: GlobalState.wifiSsid !== "" ? GlobalState.wifiSsid : "Wi-Fi"
|
||||
icon: "assets/wifi.svg"
|
||||
active: GlobalState.wifiConnected
|
||||
onClicked: {
|
||||
let proc = Quickshell.createProcess("sh", ["-c", "nm-connection-editor || foot -e nmtui"])
|
||||
proc.start()
|
||||
}
|
||||
}
|
||||
|
||||
ToggleCard {
|
||||
title: "Bluetooth"
|
||||
icon: "assets/bluetooth.svg"
|
||||
active: false // Adjust if there's a bluetooth state
|
||||
onClicked: {
|
||||
let proc = Quickshell.createProcess("sh", ["-c", "foot -e bluetoothctl"])
|
||||
proc.start()
|
||||
}
|
||||
}
|
||||
|
||||
ToggleCard {
|
||||
property bool dndActive: false
|
||||
title: "Do Not Disturb"
|
||||
icon: "" // Optional DND icon
|
||||
active: dndActive
|
||||
onClicked: dndActive = !dndActive
|
||||
}
|
||||
|
||||
ToggleCard {
|
||||
title: GlobalState.volumeMuted ? "Muted" : "Sound"
|
||||
icon: "" // Optional sound icon
|
||||
active: !GlobalState.volumeMuted
|
||||
onClicked: GlobalState.toggleVolumeMute()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section 2: Volume
|
||||
ColumnLayout {
|
||||
id: sectionVolume
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
SectionHeader { sectionNum: "02"; title: "Volume" }
|
||||
|
||||
CustomSlider {
|
||||
Layout.fillWidth: true
|
||||
value: GlobalState.volume
|
||||
onValueChangedUser: (val) => GlobalState.volume = val // Adjust to actual volume setter if needed
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
text: GlobalState.volumeMuted ? "Unmute" : "Mute"
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: GlobalState.toggleVolumeMute()
|
||||
}
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
Text {
|
||||
text: "Sound Preferences..."
|
||||
color: Theme.textMuted
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = Theme.textPrimary
|
||||
onExited: parent.color = Theme.textMuted
|
||||
onClicked: {
|
||||
let proc = Quickshell.createProcess("pavucontrol", [])
|
||||
proc.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section 3: Brightness
|
||||
ColumnLayout {
|
||||
id: sectionBrightness
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
SectionHeader { sectionNum: "03"; title: "Brightness" }
|
||||
|
||||
CustomSlider {
|
||||
Layout.fillWidth: true
|
||||
value: GlobalState.brightness
|
||||
onValueChangedUser: (val) => GlobalState.setBrightness(val)
|
||||
}
|
||||
}
|
||||
|
||||
// Section 4: Performance
|
||||
ColumnLayout {
|
||||
id: sectionPerformance
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
SectionHeader { sectionNum: "04"; title: "Performance" }
|
||||
|
||||
ProgressBarItem {
|
||||
label: "CPU"
|
||||
percent: GlobalState.cpuPercent
|
||||
valueText: GlobalState.cpuPercent + "%"
|
||||
barColor: GlobalState.cpuPercent > 80 ? Theme.accentCoral : Theme.accentVolt
|
||||
}
|
||||
|
||||
ProgressBarItem {
|
||||
label: "RAM"
|
||||
percent: (GlobalState.memUsedGb / Math.max(1, GlobalState.memTotalGb)) * 100
|
||||
valueText: GlobalState.memUsedGb + " / " + GlobalState.memTotalGb + " GB"
|
||||
}
|
||||
|
||||
ProgressBarItem {
|
||||
label: "VRAM"
|
||||
percent: (GlobalState.gpuVramUsed / Math.max(1, GlobalState.gpuVramTotal)) * 100
|
||||
valueText: GlobalState.gpuVramUsed + " / " + GlobalState.gpuVramTotal + " GB"
|
||||
}
|
||||
}
|
||||
|
||||
// Section 5: Network
|
||||
ColumnLayout {
|
||||
id: sectionNetwork
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
SectionHeader { sectionNum: "05"; title: "Network" }
|
||||
|
||||
RowLayout {
|
||||
spacing: 8
|
||||
Rectangle {
|
||||
width: 8
|
||||
height: 8
|
||||
radius: 4
|
||||
color: GlobalState.wifiConnected ? Theme.accentVolt : Theme.accentCoral
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.wifiConnected ? "Connected" : "Disconnected"
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 14
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "SSID: " + (GlobalState.wifiSsid !== "" ? GlobalState.wifiSsid : "None")
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "IP: " + GlobalState.ipAddress
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 13
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Network Preferences..."
|
||||
color: Theme.textMuted
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = Theme.textPrimary
|
||||
onExited: parent.color = Theme.textMuted
|
||||
onClicked: {
|
||||
let proc = Quickshell.createProcess("sh", ["-c", "nm-connection-editor || foot -e nmtui"])
|
||||
proc.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section 6: Battery
|
||||
ColumnLayout {
|
||||
id: sectionBattery
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
visible: GlobalState.batteryPresent
|
||||
SectionHeader { sectionNum: "06"; title: "Battery" }
|
||||
|
||||
RowLayout {
|
||||
spacing: 16
|
||||
Text {
|
||||
text: GlobalState.batteryPercent + "%"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 24
|
||||
color: GlobalState.batteryStatus === "Charging" ? Theme.accentVolt :
|
||||
(GlobalState.batteryPercent < 20 ? Theme.accentCoral : Theme.textPrimary)
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.batteryStatus
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 14
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section 7: Now Playing
|
||||
ColumnLayout {
|
||||
id: sectionNowPlaying
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
visible: GlobalState.mediaTitle !== ""
|
||||
SectionHeader { sectionNum: "07"; title: "Now Playing" }
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 4
|
||||
Text {
|
||||
text: GlobalState.mediaTitle
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.bold: true
|
||||
font.pixelSize: 14
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.mediaArtist
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 12
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 16
|
||||
|
||||
Text {
|
||||
text: "⏮"
|
||||
font.pixelSize: 20
|
||||
color: Theme.textSecondary
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -10
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = Theme.accentVolt
|
||||
onExited: parent.color = Theme.textSecondary
|
||||
onClicked: GlobalState.mediaPrevious()
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.mediaStatus === "Playing" ? "⏸" : "▶"
|
||||
font.pixelSize: 24
|
||||
color: Theme.textSecondary
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -10
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = Theme.accentVolt
|
||||
onExited: parent.color = Theme.textSecondary
|
||||
onClicked: GlobalState.mediaPlayPause()
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: "⏭"
|
||||
font.pixelSize: 20
|
||||
color: Theme.textSecondary
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -10
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = Theme.accentVolt
|
||||
onExited: parent.color = Theme.textSecondary
|
||||
onClicked: GlobalState.mediaNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section 8: Calendar
|
||||
ColumnLayout {
|
||||
id: sectionCalendar
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
SectionHeader { sectionNum: "08"; title: "Calendar" }
|
||||
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
Text {
|
||||
text: GlobalState.timeString
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 22
|
||||
color: Theme.accentVolt
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.fullDateString
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
color: Theme.textSecondary
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
columns: 7
|
||||
columnSpacing: 4
|
||||
rowSpacing: 4
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Repeater {
|
||||
model: ["S", "M", "T", "W", "T", "F", "S"]
|
||||
Text {
|
||||
text: modelData
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 11
|
||||
color: Theme.textMuted
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.preferredWidth: 32
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: 31
|
||||
Rectangle {
|
||||
property bool isToday: (index + 1) === new Date().getDate()
|
||||
Layout.preferredWidth: 32
|
||||
Layout.preferredHeight: 32
|
||||
color: isToday ? Theme.accentVolt : "transparent"
|
||||
radius: isToday ? 0 : 4
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: index + 1
|
||||
color: parent.isToday ? "#ffffff" : Theme.textSecondary
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: if (!parent.isToday) parent.color = Qt.rgba(1, 1, 1, 0.04)
|
||||
onExited: if (!parent.isToday) parent.color = "transparent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.preferredHeight: 20 } // Bottom padding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-scroll to active section when changed
|
||||
Connections {
|
||||
target: GlobalState
|
||||
function onSystemHudActiveSectionChanged() {
|
||||
if (!GlobalState.systemHudVisible) return;
|
||||
|
||||
let targetY = 0;
|
||||
if (GlobalState.systemHudActiveSection === "volume") targetY = sectionVolume.y;
|
||||
else if (GlobalState.systemHudActiveSection === "brightness") targetY = sectionBrightness.y;
|
||||
else if (GlobalState.systemHudActiveSection === "performance") targetY = sectionPerformance.y;
|
||||
else if (GlobalState.systemHudActiveSection === "network") targetY = sectionNetwork.y;
|
||||
else if (GlobalState.systemHudActiveSection === "battery") targetY = sectionBattery.y;
|
||||
else if (GlobalState.systemHudActiveSection === "nowplaying") targetY = sectionNowPlaying.y;
|
||||
else if (GlobalState.systemHudActiveSection === "calendar") targetY = sectionCalendar.y;
|
||||
|
||||
if (targetY > 0) {
|
||||
// Ensure targetY doesn't scroll past max possible scroll
|
||||
let maxY = Math.max(0, contentLayout.height - scrollView.height);
|
||||
scrollView.ScrollBar.vertical.position = Math.min(targetY, maxY) / contentLayout.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
257
home/hypr/quickshell/components/SystemInfo.qml
Normal file
257
home/hypr/quickshell/components/SystemInfo.qml
Normal file
@@ -0,0 +1,257 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Io
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: systemInfoDialog
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.keyboardFocus: visible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
bottom: true
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
|
||||
visible: GlobalState.aboutMacVisible
|
||||
color: Qt.rgba(0, 0, 0, 0.35)
|
||||
|
||||
// Close on click outside or Escape
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: GlobalState.aboutMacVisible = false
|
||||
}
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
Keys.onEscapePressed: GlobalState.aboutMacVisible = false
|
||||
}
|
||||
|
||||
property string cpuName: ""
|
||||
property string gpuName: ""
|
||||
|
||||
// Process to get CPU info
|
||||
Process {
|
||||
id: cpuProcess
|
||||
command: ["sh", "-c", "grep 'model name' /proc/cpuinfo | head -n1 | cut -d':' -f2 | xargs"]
|
||||
running: true
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const val = String(data).trim();
|
||||
if (val.length > 0) systemInfoDialog.cpuName = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process to get GPU info
|
||||
Process {
|
||||
id: gpuProcess
|
||||
command: ["sh", "-c", "nvidia-smi --query-gpu=name --format=csv,noheader | head -n1"]
|
||||
running: true
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const val = String(data).trim();
|
||||
if (val.length > 0) systemInfoDialog.gpuName = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: dialogBox
|
||||
width: 480
|
||||
height: 320
|
||||
anchors.centerIn: parent
|
||||
color: Theme.glassBg
|
||||
border.color: Theme.glassBorder
|
||||
border.width: 1
|
||||
radius: 0
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
// Eat clicks so they don't close the dialog
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
// Header bar
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 40
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: closeBtn
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.left: parent.left
|
||||
color: closeMouseArea.containsMouse ? Theme.accentCoral : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "✕"
|
||||
color: closeMouseArea.containsMouse ? Theme.textPrimary : Theme.textSecondary
|
||||
font.pixelSize: 14
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: closeMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: GlobalState.aboutMacVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "System Info"
|
||||
font.family: Theme.fontSerif
|
||||
font.italic: true
|
||||
font.pixelSize: 15
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
}
|
||||
|
||||
// Body
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "Silicon Volt"
|
||||
font.family: Theme.fontSerif
|
||||
font.italic: true
|
||||
font.pixelSize: 24
|
||||
color: Theme.accentVolt
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "NixOS // Hyprland"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
color: Theme.textMuted
|
||||
bottomPadding: 16
|
||||
}
|
||||
|
||||
Grid {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
columns: 2
|
||||
spacing: 12
|
||||
rowSpacing: 8
|
||||
|
||||
// HOST
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "HOST"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { text: "hades"; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
|
||||
// CPU
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "CPU"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { id: cpuText; text: systemInfoDialog.cpuName || "Loading..."; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
|
||||
// MEMORY
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "MEMORY"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { text: GlobalState.memUsedGb + " / " + GlobalState.memTotalGb + " GB"; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
|
||||
// GPU
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "GPU"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { id: gpuText; text: systemInfoDialog.gpuName || "Loading..."; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
|
||||
// VRAM
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "VRAM"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { text: GlobalState.gpuVramUsed + " / " + GlobalState.gpuVramTotal + " GB"; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
|
||||
// WM
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "WM"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { text: "Hyprland"; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
|
||||
// OS
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "OS"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { text: "NixOS"; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Footer bar
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 44
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
|
||||
component FooterButton: Rectangle {
|
||||
id: btn
|
||||
property string text: ""
|
||||
property alias command: proc.command
|
||||
|
||||
width: btnText.width + 24
|
||||
height: 28
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: btnMouse.containsMouse ? Qt.rgba(Theme.accentVolt.r, Theme.accentVolt.g, Theme.accentVolt.b, 0.1) : "transparent"
|
||||
border.color: Theme.glassBorder
|
||||
border.width: 1
|
||||
radius: 0
|
||||
|
||||
Text {
|
||||
id: btnText
|
||||
anchors.centerIn: parent
|
||||
text: btn.text
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 12
|
||||
color: btnMouse.containsMouse ? Theme.accentVolt : Theme.textMuted
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: btnMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: proc.running = true
|
||||
}
|
||||
|
||||
Process {
|
||||
id: proc
|
||||
}
|
||||
}
|
||||
|
||||
FooterButton {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 16
|
||||
text: "System Report..."
|
||||
command: ["foot", "-e", "btop"]
|
||||
}
|
||||
|
||||
FooterButton {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
text: "Software Update..."
|
||||
command: ["foot", "-e", "sudo", "nixos-rebuild", "dry-activate"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
101
home/hypr/quickshell/components/TopStrip.qml
Normal file
101
home/hypr/quickshell/components/TopStrip.qml
Normal file
@@ -0,0 +1,101 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
property var modelData
|
||||
screen: modelData
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
|
||||
margins.left: Theme.sidebarWidth
|
||||
|
||||
implicitHeight: Theme.topStripHeight
|
||||
color: Qt.rgba(Theme.bgPrimary.r, Theme.bgPrimary.g, Theme.bgPrimary.b, 0.92)
|
||||
exclusiveZone: Theme.topStripHeight
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
WlrLayershell.namespace: "quickshell-topstrip"
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
Rectangle {
|
||||
id: bottomBorder
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
spacing: 16
|
||||
|
||||
// Left Section
|
||||
Text {
|
||||
id: workspaceIndicator
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
color: Theme.textMuted
|
||||
|
||||
function pad(num) {
|
||||
if (num === undefined || num === null) return "00";
|
||||
return num < 10 ? "0" + num : num.toString();
|
||||
}
|
||||
|
||||
text: pad(GlobalState.activeWorkspace) + " // " + (GlobalState.workspaceNames[GlobalState.activeWorkspace] !== undefined ? GlobalState.workspaceNames[GlobalState.activeWorkspace] : "main")
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 150 }
|
||||
}
|
||||
}
|
||||
|
||||
// Center Section
|
||||
Text {
|
||||
id: windowTitle
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.family: Theme.fontSerif
|
||||
font.italic: true
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.textSecondary
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
|
||||
text: GlobalState.activeWindowTitle
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 150 }
|
||||
}
|
||||
}
|
||||
|
||||
// Right Section
|
||||
Text {
|
||||
id: clock
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
color: Theme.textPrimary
|
||||
text: GlobalState.timeString
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 150 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,55 +25,60 @@ Scope {
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "controlCenter"
|
||||
target: "systemHud"
|
||||
function toggle() {
|
||||
GlobalState.toggleControlCenter();
|
||||
GlobalState.toggleSystemHud();
|
||||
}
|
||||
function open() {
|
||||
GlobalState.controlCenterVisible = true;
|
||||
GlobalState.systemHudVisible = true;
|
||||
}
|
||||
function close() {
|
||||
GlobalState.controlCenterVisible = false;
|
||||
GlobalState.systemHudVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "aboutMac"
|
||||
target: "systemInfo"
|
||||
function toggle() {
|
||||
GlobalState.toggleAboutMac();
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// MULTI-MONITOR BARS & DOCKS
|
||||
// LEFT SIDEBAR (Primary monitor only)
|
||||
// =========================================================================
|
||||
// 1. macOS Catalina Top Menu Bar (Spawned per monitor)
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
MenuBar {}
|
||||
SidePanel {
|
||||
screen: Quickshell.screens[0]
|
||||
}
|
||||
|
||||
// 2. macOS Catalina Floating Dock (Spawned per monitor)
|
||||
// =========================================================================
|
||||
// TOP STATUS STRIP (All monitors)
|
||||
// =========================================================================
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
Dock {}
|
||||
TopStrip {}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// GLOBAL MODAL OVERLAYS
|
||||
// =========================================================================
|
||||
// 3. Spotlight Search Overlay
|
||||
// Spotlight Search Overlay
|
||||
Spotlight {
|
||||
id: spotlightOverlay
|
||||
}
|
||||
|
||||
// 4. Control Center & Notification Center Sidebar
|
||||
ControlCenter {
|
||||
id: controlCenterSidebar
|
||||
// System HUD Flyout Panel
|
||||
SystemHUD {
|
||||
id: systemHudPanel
|
||||
}
|
||||
|
||||
// 5. About This Mac Dialog
|
||||
AboutMac {
|
||||
id: aboutMacDialog
|
||||
// Quick Menu (Power/Session Menu)
|
||||
QuickMenu {
|
||||
id: quickMenuOverlay
|
||||
}
|
||||
|
||||
// System Info Dialog
|
||||
SystemInfo {
|
||||
id: systemInfoDialog
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,56 +2,45 @@ pragma Singleton
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
// macOS Catalina Color Palette
|
||||
readonly property color menuBarBg: Qt.rgba(0.12, 0.12, 0.14, 0.88)
|
||||
readonly property color menuBarBorder: Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
|
||||
readonly property color dockBg: Qt.rgba(0.15, 0.16, 0.18, 0.72)
|
||||
readonly property color dockBorder: Qt.rgba(1.0, 1.0, 1.0, 0.22)
|
||||
readonly property color dockHighlight: Qt.rgba(1.0, 1.0, 1.0, 0.35)
|
||||
readonly property color dockShadow: Qt.rgba(0.0, 0.0, 0.0, 0.45)
|
||||
readonly property color dockDot: Qt.rgba(1.0, 1.0, 1.0, 0.95)
|
||||
|
||||
readonly property color windowBg: Qt.rgba(0.14, 0.14, 0.16, 0.94)
|
||||
readonly property color windowBorder: Qt.rgba(1.0, 1.0, 1.0, 0.15)
|
||||
readonly property color cardBg: Qt.rgba(0.22, 0.22, 0.26, 0.65)
|
||||
readonly property color cardBorder: Qt.rgba(1.0, 1.0, 1.0, 0.10)
|
||||
|
||||
readonly property color menuDropdownBg: Qt.rgba(0.16, 0.16, 0.18, 0.96)
|
||||
readonly property color menuDropdownBorder: Qt.rgba(1.0, 1.0, 1.0, 0.18)
|
||||
readonly property color menuHoverBlue: "#0062E3"
|
||||
readonly property color menuTextHover: "#FFFFFF"
|
||||
|
||||
readonly property color accentBlue: "#0A84FF"
|
||||
readonly property color accentGreen: "#30D158"
|
||||
readonly property color accentRed: "#FF453A"
|
||||
readonly property color accentYellow: "#FFD60A"
|
||||
readonly property color accentOrange: "#FF9F0A"
|
||||
|
||||
// Colors
|
||||
readonly property color bgPrimary: "#131313"
|
||||
readonly property color bgSecondary: "#0e0e0e"
|
||||
readonly property color glassBg: "#1c1b1b"
|
||||
readonly property color glassBorder: Qt.rgba(1.0, 1.0, 1.0, 0.08)
|
||||
readonly property color glassBorderHover: Qt.rgba(1.0, 1.0, 1.0, 0.18)
|
||||
readonly property color accentVolt: "#CFFC00"
|
||||
readonly property color accentVoltGlow: Qt.rgba(0.812, 0.988, 0.0, 0.25)
|
||||
readonly property color accentVoltLight: "#e3ff66"
|
||||
readonly property color accentBlue: "#00BFFF"
|
||||
readonly property color accentCoral: "#FF7A59"
|
||||
readonly property color textPrimary: "#FFFFFF"
|
||||
readonly property color textSecondary: Qt.rgba(1.0, 1.0, 1.0, 0.72)
|
||||
readonly property color textTertiary: Qt.rgba(1.0, 1.0, 1.0, 0.45)
|
||||
readonly property color textSecondary: "#e5e2e1"
|
||||
readonly property color textMuted: "#ADAAAA"
|
||||
readonly property color textDisabled: Qt.rgba(1.0, 1.0, 1.0, 0.25)
|
||||
|
||||
// Typography
|
||||
readonly property string fontFamily: "SF Pro Display, SF Pro Text, Helvetica Neue, Cantarell, Liberation Sans, sans-serif"
|
||||
readonly property int fontSizeMenuBar: 13
|
||||
readonly property string fontSerif: "Instrument Serif, Georgia, serif"
|
||||
readonly property string fontSans: "IBM Plex Sans, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif"
|
||||
readonly property string fontMono: "Nanum Gothic Coding, JetBrains Mono, monospace"
|
||||
|
||||
readonly property int fontSizeSmall: 11
|
||||
readonly property int fontSizeNormal: 13
|
||||
readonly property int fontSizeLarge: 15
|
||||
readonly property int fontSizeTitle: 19
|
||||
readonly property int fontSizeSpotlight: 20
|
||||
readonly property int fontSizeDisplay: 24
|
||||
readonly property int fontSizeWorkspace: 12
|
||||
|
||||
// Geometry & Radii
|
||||
readonly property int menuBarHeight: 26
|
||||
readonly property int radiusSmall: 4
|
||||
readonly property int radiusMedium: 8
|
||||
readonly property int radiusLarge: 14
|
||||
readonly property int radiusDock: 18
|
||||
readonly property int radiusModal: 16
|
||||
// Geometry
|
||||
readonly property int radiusNone: 0
|
||||
readonly property int sidebarWidth: 52
|
||||
readonly property int topStripHeight: 28
|
||||
readonly property int hudWidth: 360
|
||||
readonly property int iconSize: 36
|
||||
readonly property int iconSizeSmall: 20
|
||||
readonly property int workspaceIndicatorWidth: 2
|
||||
|
||||
// Animation Durations
|
||||
readonly property int animFast: 120
|
||||
readonly property int animNormal: 220
|
||||
readonly property int animSmooth: 320
|
||||
readonly property int animSmooth: 400
|
||||
readonly property int animFast: 200
|
||||
readonly property int animBounce: 600
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user