feat: basic quickshell bar
This commit is contained in:
parent
3c579d0e27
commit
c2e78cc11c
11 changed files with 615 additions and 0 deletions
108
config/Appearance.qml
Normal file
108
config/Appearance.qml
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
import Qt.labs.platform
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property bool borders: true
|
||||
|
||||
readonly property QtObject transparency: QtObject {
|
||||
property real base: 0.58
|
||||
property real layers: 0.3
|
||||
}
|
||||
|
||||
readonly property QtObject rounding: QtObject {
|
||||
readonly property int small: 12
|
||||
readonly property int normal: 17
|
||||
readonly property int large: 25
|
||||
readonly property int full: 1000
|
||||
}
|
||||
|
||||
readonly property QtObject spacing: QtObject {
|
||||
readonly property int small: 7
|
||||
readonly property int smaller: 10
|
||||
readonly property int normal: 12
|
||||
readonly property int larger: 15
|
||||
readonly property int large: 20
|
||||
}
|
||||
|
||||
readonly property QtObject padding: QtObject {
|
||||
readonly property int small: 5
|
||||
readonly property int smaller: 7
|
||||
readonly property int normal: 10
|
||||
readonly property int larger: 12
|
||||
readonly property int large: 15
|
||||
}
|
||||
|
||||
readonly property QtObject font: QtObject {
|
||||
readonly property QtObject family: QtObject {
|
||||
readonly property string sans: "IBM Plex Sans"
|
||||
readonly property string mono: "JetBrains Mono NF"
|
||||
readonly property string material: "Material Symbols Rounded"
|
||||
}
|
||||
|
||||
readonly property QtObject size: QtObject {
|
||||
readonly property int small: 11
|
||||
readonly property int smaller: 12
|
||||
readonly property int normal: 13
|
||||
readonly property int larger: 15
|
||||
readonly property int large: 18
|
||||
}
|
||||
}
|
||||
|
||||
readonly property QtObject colours: QtObject {
|
||||
property color primary: "#85D2E7"
|
||||
property color secondary: "#B2CBD3"
|
||||
property color tertiary: "#BFC4EB"
|
||||
property color text: "#DEE3E6"
|
||||
property color subtext1: "#BFC8CB"
|
||||
property color subtext0: "#899295"
|
||||
property color overlay2: "#788083"
|
||||
property color overlay1: "#666D70"
|
||||
property color overlay0: "#555C5E"
|
||||
property color surface2: "#434A4D"
|
||||
property color surface1: "#32393B"
|
||||
property color surface0: "#202628"
|
||||
property color base: "#0F1416"
|
||||
property color mantle: "#090C0D"
|
||||
property color crust: "#050607"
|
||||
property color success: "#93E5B6"
|
||||
property color error: "#EA8DC1"
|
||||
property color rosewater: "#9BD4A1"
|
||||
property color flamingo: "#84D5C3"
|
||||
property color pink: "#8CD0F1"
|
||||
property color mauve: "#91CEF5"
|
||||
property color red: "#80D4DC"
|
||||
property color maroon: "#85D2E7"
|
||||
property color peach: "#80D5D0"
|
||||
property color yellow: "#93D5A9"
|
||||
property color green: "#8DD5B3"
|
||||
property color teal: "#81D3E0"
|
||||
property color sky: "#83D2E4"
|
||||
property color sapphire: "#8AD1EE"
|
||||
property color blue: "#9CCBFA"
|
||||
property color lavender: "#86D1EB"
|
||||
}
|
||||
|
||||
function alpha(c: color, layer: bool): color {
|
||||
return Qt.rgba(c.r, c.g, c.b, layer ? transparency.layers : transparency.base);
|
||||
}
|
||||
|
||||
FileView {
|
||||
path: `${StandardPaths.standardLocations(StandardPaths.GenericStateLocation)[0]}/caelestia/scheme/current.txt`
|
||||
watchChanges: true
|
||||
onFileChanged: this.reload()
|
||||
onLoaded: {
|
||||
const contents = this.text();
|
||||
|
||||
for (const line of contents.split("\n")) {
|
||||
const [name, colour] = line.split(" ");
|
||||
root.colours[name.trim()] = `#${colour.trim()}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
modules/bar/ActiveWindow.qml
Normal file
29
modules/bar/ActiveWindow.qml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import "root:/widgets"
|
||||
import "root:/services"
|
||||
import "root:/utils"
|
||||
import "root:/config"
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Box {
|
||||
id: root
|
||||
property color colour: Appearance.colours.pink
|
||||
|
||||
MaterialIcon {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
text: Icons.getAppCategoryIcon(Hyprland.activeClient?.wmClass) ?? "desktop_windows"
|
||||
color: root.colour
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
text: Hyprland.activeClient?.title ?? "Desktop"
|
||||
font.pointSize: Appearance.font.size.smaller
|
||||
font.family: Appearance.font.family.mono
|
||||
color: root.colour
|
||||
|
||||
rotation: root.vertical ? 90 : 0
|
||||
Layout.maximumWidth: root.vertical ? this.implicitHeight : this.implicitWidth
|
||||
}
|
||||
}
|
||||
48
modules/bar/Bar.qml
Normal file
48
modules/bar/Bar.qml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import "root:/widgets"
|
||||
import "root:/config"
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
|
||||
WlrLayershell {
|
||||
id: win
|
||||
|
||||
property var modelData
|
||||
property bool vertical: false
|
||||
|
||||
screen: modelData
|
||||
namespace: "caelestia-bar"
|
||||
color: Appearance.alpha(Appearance.colours.base, false)
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: !vertical
|
||||
bottom: vertical
|
||||
}
|
||||
|
||||
width: contents.implicitWidth + (vertical ? Appearance.padding.normal * 2 : 0)
|
||||
height: contents.implicitHeight + (vertical ? 0 : Appearance.padding.smaller * 2)
|
||||
|
||||
Box {
|
||||
id: contents
|
||||
|
||||
vertical: win.vertical
|
||||
spacing: Appearance.spacing.larger
|
||||
x: Appearance.padding.normal
|
||||
y: vertical ? Appearance.padding.normal : Appearance.padding.smaller
|
||||
|
||||
OsIcon {}
|
||||
|
||||
Clock {
|
||||
vertical: win.vertical
|
||||
}
|
||||
|
||||
ActiveWindow {
|
||||
vertical: win.vertical
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
modules/bar/Clock.qml
Normal file
26
modules/bar/Clock.qml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import "root:/widgets"
|
||||
import "root:/services"
|
||||
import "root:/config"
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Box {
|
||||
id: root
|
||||
property color colour: Appearance.colours.peach
|
||||
|
||||
MaterialIcon {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
text: "calendar_month"
|
||||
color: root.colour
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
horizontalAlignment: Text.AlignJustify
|
||||
|
||||
text: root.vertical ? Time.format("hh\nmm") : Time.format("dd/MM/yy hh:mm")
|
||||
font.pointSize: Appearance.font.size.smaller
|
||||
font.family: Appearance.font.family.mono
|
||||
color: root.colour
|
||||
}
|
||||
}
|
||||
15
modules/bar/OsIcon.qml
Normal file
15
modules/bar/OsIcon.qml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import "root:/widgets"
|
||||
import "root:/services"
|
||||
import "root:/utils"
|
||||
import "root:/config"
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
text: Icons.osIcon
|
||||
font.pointSize: Appearance.font.size.smaller
|
||||
font.family: Appearance.font.family.mono
|
||||
color: Appearance.colours.yellow
|
||||
}
|
||||
159
services/Hyprland.qml
Normal file
159
services/Hyprland.qml
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Hyprland
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property list<var> clients: []
|
||||
property list<var> monitors: []
|
||||
property list<var> workspaces: []
|
||||
property var activeClient: null
|
||||
property var activeWorkspace: null
|
||||
property var focusedMonitor: null
|
||||
|
||||
function reload() {
|
||||
getClients.running = true;
|
||||
getMonitors.running = true;
|
||||
getWorkspaces.running = true;
|
||||
getActiveClient.running = true;
|
||||
getActiveWorkspace.running = true;
|
||||
}
|
||||
|
||||
Component.onCompleted: reload()
|
||||
|
||||
Connections {
|
||||
target: Hyprland
|
||||
function onRawEvent(event: string): void {
|
||||
if (!event.endsWith("v2"))
|
||||
root.reload();
|
||||
}
|
||||
}
|
||||
|
||||
component HyprData: Process {
|
||||
id: proc
|
||||
|
||||
required property string type
|
||||
property string prop: type
|
||||
property bool array: true
|
||||
function transform(data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
command: ["bash", "-c", `hyprctl -j ${type} | jq -c`]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
root[proc.prop] = proc.array ? JSON.parse(data).map(proc.transform) : proc.transform(JSON.parse(data));
|
||||
if (proc.type === "monitors")
|
||||
root.focusedMonitor = root.monitors.find(m => m.focused);
|
||||
}
|
||||
}
|
||||
|
||||
function transformClient(client) {
|
||||
if (!client.address)
|
||||
return null;
|
||||
|
||||
return {
|
||||
address: client.address,
|
||||
x: client.at[0],
|
||||
y: client.at[1],
|
||||
width: client.size[0],
|
||||
height: client.size[1],
|
||||
workspace: transformWorkspace(client.workspace),
|
||||
floating: client.floating,
|
||||
monitor: client.monitor,
|
||||
wmClass: client.class,
|
||||
title: client.title,
|
||||
initialClass: client.initialClass,
|
||||
initialTitle: client.initialTitle,
|
||||
pid: client.pid,
|
||||
xwayland: client.xwayland,
|
||||
pinned: client.pinned,
|
||||
fullscreen: client.fullscreen,
|
||||
focusHistoryId: client.focusHistoryID,
|
||||
inhibitingIdle: client.inhibitingIdle
|
||||
};
|
||||
}
|
||||
|
||||
function transformMonitor(monitor) {
|
||||
return {
|
||||
id: monitor.id,
|
||||
name: monitor.name,
|
||||
description: monitor.description,
|
||||
make: monitor.make,
|
||||
model: monitor.model,
|
||||
serial: monitor.serial,
|
||||
x: monitor.x,
|
||||
y: monitor.y,
|
||||
width: monitor.width,
|
||||
height: monitor.height,
|
||||
refreshRate: monitor.refreshRate,
|
||||
activeWorkspace: transformWorkspace(monitor.activeWorkspace),
|
||||
specialWorkspace: transformWorkspace(monitor.specialWorkspace),
|
||||
reserved: monitor.reserved,
|
||||
scale: monitor.scale,
|
||||
transform: monitor.transform,
|
||||
focused: monitor.focused,
|
||||
dpms: monitor.dpms,
|
||||
vrr: monitor.vrr,
|
||||
disabled: monitor.disabled
|
||||
};
|
||||
}
|
||||
|
||||
function transformWorkspace(workspace) {
|
||||
return {
|
||||
id: workspace.id,
|
||||
name: workspace.name,
|
||||
special: workspace.name.startsWith("special:")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
HyprData {
|
||||
id: getClients
|
||||
type: "clients"
|
||||
function transform(client) {
|
||||
return transformClient(client);
|
||||
}
|
||||
}
|
||||
|
||||
HyprData {
|
||||
id: getMonitors
|
||||
type: "monitors"
|
||||
function transform(monitor) {
|
||||
return transformMonitor(monitor);
|
||||
}
|
||||
}
|
||||
|
||||
HyprData {
|
||||
id: getWorkspaces
|
||||
type: "workspaces"
|
||||
function transform(workspace) {
|
||||
return transformWorkspace(workspace);
|
||||
}
|
||||
}
|
||||
|
||||
HyprData {
|
||||
id: getActiveClient
|
||||
type: "activewindow"
|
||||
prop: "activeClient"
|
||||
array: false
|
||||
function transform(client) {
|
||||
return transformClient(client);
|
||||
}
|
||||
}
|
||||
|
||||
HyprData {
|
||||
id: getActiveWorkspace
|
||||
type: "activeworkspace"
|
||||
prop: "activeWorkspace"
|
||||
array: false
|
||||
function transform(workspace) {
|
||||
return transformWorkspace(workspace);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
services/Time.qml
Normal file
20
services/Time.qml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
property alias enabled: clock.enabled
|
||||
readonly property date date: clock.date
|
||||
readonly property int hours: clock.hours
|
||||
readonly property int minutes: clock.minutes
|
||||
readonly property int seconds: clock.seconds
|
||||
|
||||
function format(fmt: string): string {
|
||||
return Qt.formatDateTime(clock.date, fmt);
|
||||
}
|
||||
|
||||
SystemClock {
|
||||
id: clock
|
||||
precision: SystemClock.Seconds
|
||||
}
|
||||
}
|
||||
6
shell.qml
Normal file
6
shell.qml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import "modules/bar"
|
||||
import Quickshell
|
||||
|
||||
ShellRoot {
|
||||
Bar {}
|
||||
}
|
||||
181
utils/Icons.qml
Normal file
181
utils/Icons.qml
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property var osIcons: ({
|
||||
almalinux: "",
|
||||
alpine: "",
|
||||
arch: "",
|
||||
archcraft: "",
|
||||
arcolinux: "",
|
||||
artix: "",
|
||||
centos: "",
|
||||
debian: "",
|
||||
devuan: "",
|
||||
elementary: "",
|
||||
endeavouros: "",
|
||||
fedora: "",
|
||||
freebsd: "",
|
||||
garuda: "",
|
||||
gentoo: "",
|
||||
hyperbola: "",
|
||||
kali: "",
|
||||
linuxmint: "",
|
||||
mageia: "",
|
||||
openmandriva: "",
|
||||
manjaro: "",
|
||||
neon: "",
|
||||
nixos: "",
|
||||
opensuse: "",
|
||||
suse: "",
|
||||
sles: "",
|
||||
sles_sap: "",
|
||||
"opensuse-tumbleweed": "",
|
||||
parrot: "",
|
||||
pop: "",
|
||||
raspbian: "",
|
||||
rhel: "",
|
||||
rocky: "",
|
||||
slackware: "",
|
||||
solus: "",
|
||||
steamos: "",
|
||||
tails: "",
|
||||
trisquel: "",
|
||||
ubuntu: "",
|
||||
vanilla: "",
|
||||
void: "",
|
||||
zorin: ""
|
||||
})
|
||||
|
||||
readonly property var weatherIcons: ({
|
||||
warning: "",
|
||||
sunny: "",
|
||||
clear: "",
|
||||
partly_cloudy: "",
|
||||
partly_cloudy_night: "",
|
||||
cloudy: "",
|
||||
overcast: "",
|
||||
mist: "",
|
||||
patchy_rain_nearby: "",
|
||||
patchy_rain_possible: "",
|
||||
patchy_snow_possible: "",
|
||||
patchy_sleet_possible: "",
|
||||
patchy_freezing_drizzle_possible: "",
|
||||
thundery_outbreaks_possible: "",
|
||||
blowing_snow: "",
|
||||
blizzard: "",
|
||||
fog: "",
|
||||
freezing_fog: "",
|
||||
patchy_light_drizzle: "",
|
||||
light_drizzle: "",
|
||||
freezing_drizzle: "",
|
||||
heavy_freezing_drizzle: "",
|
||||
patchy_light_rain: "",
|
||||
light_rain: "",
|
||||
moderate_rain_at_times: "",
|
||||
moderate_rain: "",
|
||||
heavy_rain_at_times: "",
|
||||
heavy_rain: "",
|
||||
light_freezing_rain: "",
|
||||
moderate_or_heavy_freezing_rain: "",
|
||||
light_sleet: "",
|
||||
moderate_or_heavy_sleet: "",
|
||||
patchy_light_snow: "",
|
||||
light_snow: "",
|
||||
patchy_moderate_snow: "",
|
||||
moderate_snow: "",
|
||||
patchy_heavy_snow: "",
|
||||
heavy_snow: "",
|
||||
ice_pellets: "",
|
||||
light_rain_shower: "",
|
||||
moderate_or_heavy_rain_shower: "",
|
||||
torrential_rain_shower: "",
|
||||
light_sleet_showers: "",
|
||||
moderate_or_heavy_sleet_showers: "",
|
||||
light_snow_showers: "",
|
||||
moderate_or_heavy_snow_showers: "",
|
||||
light_showers_of_ice_pellets: "",
|
||||
moderate_or_heavy_showers_of_ice_pellets: "",
|
||||
patchy_light_rain_with_thunder: "",
|
||||
moderate_or_heavy_rain_with_thunder: "",
|
||||
moderate_or_heavy_rain_in_area_with_thunder: "",
|
||||
patchy_light_snow_with_thunder: "",
|
||||
moderate_or_heavy_snow_with_thunder: ""
|
||||
})
|
||||
|
||||
readonly property var desktopEntrySubs: ({
|
||||
Firefox: "firefox"
|
||||
})
|
||||
|
||||
readonly property var categoryIcons: ({
|
||||
WebBrowser: "web",
|
||||
Printing: "print",
|
||||
Security: "security",
|
||||
Network: "chat",
|
||||
Archiving: "archive",
|
||||
Compression: "archive",
|
||||
Development: "code",
|
||||
IDE: "code",
|
||||
TextEditor: "edit_note",
|
||||
Audio: "music_note",
|
||||
Music: "music_note",
|
||||
Player: "music_note",
|
||||
Recorder: "mic",
|
||||
Game: "sports_esports",
|
||||
FileTools: "files",
|
||||
FileManager: "files",
|
||||
Filesystem: "files",
|
||||
FileTransfer: "files",
|
||||
Settings: "settings",
|
||||
DesktopSettings: "settings",
|
||||
HardwareSettings: "settings",
|
||||
TerminalEmulator: "terminal",
|
||||
ConsoleOnly: "terminal",
|
||||
Utility: "build",
|
||||
Monitor: "monitor_heart",
|
||||
Midi: "graphic_eq",
|
||||
Mixer: "graphic_eq",
|
||||
AudioVideoEditing: "video_settings",
|
||||
AudioVideo: "music_video",
|
||||
Video: "videocam",
|
||||
Building: "construction",
|
||||
Graphics: "photo_library",
|
||||
"2DGraphics": "photo_library",
|
||||
RasterGraphics: "photo_library",
|
||||
TV: "tv",
|
||||
System: "host"
|
||||
})
|
||||
|
||||
property string osIcon: ""
|
||||
|
||||
function getAppCategoryIcon(name) {
|
||||
if (!name)
|
||||
return null;
|
||||
|
||||
const categories = DesktopEntries.applications.values.find(app => app.id === name)?.categories;
|
||||
|
||||
if (categories)
|
||||
for (const [key, value] of Object.entries(this.categoryIcons))
|
||||
if (categories.includes(key))
|
||||
return value;
|
||||
return "terminal";
|
||||
}
|
||||
|
||||
FileView {
|
||||
path: "/etc/os-release"
|
||||
onLoaded: {
|
||||
const osId = this.text().split("\n").find(l => l.startsWith("ID="))?.split("=")[1];
|
||||
if (root.osIcons.hasOwnProperty(osId))
|
||||
return root.osIcon = root.osIcons[osId];
|
||||
const osIdLike = this.text().split("\n").find(l => l.startsWith("ID_LIKE="))?.split("=")[1];
|
||||
if (osIdLike)
|
||||
for (const id of osIdLike.split(" "))
|
||||
if (root.osIcons.hasOwnProperty(id))
|
||||
return root.osIcon = root.osIcons[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
16
widgets/Box.qml
Normal file
16
widgets/Box.qml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import "root:/config"
|
||||
import QtQuick.Layouts
|
||||
|
||||
GridLayout {
|
||||
property bool vertical: false
|
||||
property real spacing: Appearance.spacing.small
|
||||
property bool homogenous: false
|
||||
|
||||
flow: vertical ? GridLayout.TopToBottom : GridLayout.LeftToRight
|
||||
uniformCellWidths: homogenous && vertical
|
||||
uniformCellHeights: homogenous && !vertical
|
||||
rows: vertical ? -1 : 1
|
||||
columns: vertical ? 1 : -1
|
||||
rowSpacing: spacing
|
||||
columnSpacing: spacing
|
||||
}
|
||||
7
widgets/MaterialIcon.qml
Normal file
7
widgets/MaterialIcon.qml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import "root:/config"
|
||||
import QtQuick
|
||||
|
||||
Text {
|
||||
font.family: Appearance.font.family.material
|
||||
font.pointSize: Appearance.font.size.larger
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue