This commit is contained in:
2025-07-23 19:17:11 +01:00
parent df2a697a9b
commit e48474bd6a
21 changed files with 0 additions and 0 deletions

47
quickshell/Audio.qml Normal file
View File

@@ -0,0 +1,47 @@
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import Quickshell.Services.Pipewire
Item {
id: root
property PwNode speakerNode: Pipewire.defaultAudioSink
property PwNode microphoneNode: Pipewire.defaultAudioSource
PwObjectTracker { objects: [ root.microphoneNode, root.speakerNode ] }
width: row.width
height: row.height
// console.log("a");
RowLayout {
id: row
IconImage {
// anchors.centerIn: parent
implicitSize: 27
source: "root:Speaker.svg"
}
Text {
id: text
text: root.speakerNode.audio.muted ? "0%" : root.speakerNode.audio.volume * 100 + "%"
font.pointSize: 10.75
color: root.speakerNode.audio.muted ? "red" : "#FFFFFF"
}
IconImage {
implicitSize: 26
source: "root:Mic.svg"
}
Text {
text: parseInt(root.microphoneNode.audio.muted ? "0" : root.microphoneNode.audio.volume * 100) + "%"
font.pointSize: 10.75
color: root.microphoneNode.audio.muted ? "red" : "#FFFFFF"
}
}
}

67
quickshell/Bar.qml Normal file
View File

@@ -0,0 +1,67 @@
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
PanelWindow {
property var modelData
screen: modelData.values[0];
color: '#20ffffff'
anchors {
top: true
left: true
right: true
}
implicitHeight: 30
RowLayout {
anchors {
fill: parent
leftMargin: 10
rightMargin: 10
}
RowLayout { // Left
Layout.alignment: Qt.AlignLeft
}
RowLayout { // Center
// TODO: add icons of the active window per workspace in the workspace tab
anchors.centerIn: parent
Workspaces {}
}
RowLayout { // Right
Layout.alignment: Qt.AlignRight
VerticalSeprator {}
Loader {
sourceComponent: Audio {}
}
RowLayout {
id: aaaaa
// If player disapear the seprator disapears with it
visible: Player.activePlayer.isPlaying()
VerticalSeprator {}
PlayerText {
}
}
VerticalSeprator {}
WrapperItem {
Text { // Date & Time
text: Time.time
color: '#FFFFFF'
font.pointSize: 10.75
}
}
// VerticalSeprator {}
}
}
Rectangle {
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
}
height: 2
color: "#8d8d8d"
}
}

34
quickshell/BarButton.qml Normal file
View File

@@ -0,0 +1,34 @@
import QtQuick
import QtQuick.Effects
FullwidthMouseArea {
id: root
property bool showPressed: mouseArea.pressed;
property real baseMargin: 0;
property bool directScale: false;
readonly property Item contentItem: mContentItem;
default property alias contentItemData: mContentItem.data;
property real targetBrightness: root.showPressed ? -25 : root.mouseArea.containsMouse && root.enabled ? 75 : 0
Behavior on targetBrightness { SmoothedAnimation { velocity: 600 } }
property real targetMargins: root.showPressed ? 3 : 0;
Behavior on targetMargins { SmoothedAnimation { velocity: 25 } }
hoverEnabled: true
Item {
id: mContentItem
anchors.fill: parent;
anchors.margins: root.baseMargin + (root.directScale ? 0 : root.targetMargins);
scale: root.directScale ? (width - root.targetMargins * 2) / width : 1.0;
opacity: root.enabled ? 1.0 : 0.5;
Behavior on opacity { SmoothedAnimation { velocity: 5 } }
layer.enabled: root.targetBrightness != 0
layer.effect: MultiEffect { brightness: root.targetBrightness / 1000 }
}
}

79
quickshell/BarContain.qml Normal file
View File

@@ -0,0 +1,79 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Wayland
PanelWindow {
id: root
default property alias barItems: containment.data;
anchors {
left: true
top: true
bottom: true
}
property real baseWidth: 55
property real leftMargin: root.compactState * 10
width: baseWidth + 15
exclusiveZone: baseWidth + (isFullscreenWorkspace ? 0 : 15) - margins.left
mask: Region {
height: root.height
width: root.exclusiveZone
}
color: "transparent"
WlrLayershell.namespace: "shell:bar"
readonly property Tooltip tooltip: tooltip;
Tooltip {
id: tooltip
bar: root
}
readonly property real tooltipXOffset: root.baseWidth + root.leftMargin + 5;
function boundedY(targetY: real, height: real): real {
return Math.max(barRect.anchors.topMargin + height, Math.min(barRect.height + barRect.anchors.topMargin - height, targetY))
}
readonly property bool isFullscreenWorkspace: Hyprland.monitorFor(screen).activeWorkspace.hasFullscreen
property real compactState: isFullscreenWorkspace ? 0 : 1
Behavior on compactState {
NumberAnimation {
duration: 600
easing.type: Easing.BezierSpline
easing.bezierCurve: [0.0, 0.75, 0.15, 1.0, 1.0, 1.0]
}
}
Rectangle {
id: barRect
x: root.leftMargin - Lock.Controller.lockSlide * (barRect.width + root.leftMargin)
width: parent.width - 15
anchors {
top: parent.top
bottom: parent.bottom
margins: root.compactState * 10
}
color: ShellGlobals.colors.bar
radius: root.compactState * 5
border.color: ShellGlobals.colors.barOutline
border.width: root.compactState
Item {
id: containment
anchors {
fill: parent
margins: 5
}
}
}
}

View File

@@ -0,0 +1,53 @@
import QtQuick
Item {
id: root
property bool fillWindowWidth: false;
property real extraVerticalMargin: 0;
property alias mouseArea: mouseArea;
property alias hoverEnabled: mouseArea.hoverEnabled;
property alias acceptedButtons: mouseArea.acceptedButtons;
property alias pressedButtons: mouseArea.pressedButtons;
property alias containsMouse: mouseArea.containsMouse;
property alias isPressed: mouseArea.pressed;
signal clicked(event: MouseEvent);
signal entered();
signal exited();
signal pressed(event: MouseEvent);
signal released(event: MouseEvent);
signal wheel(event: WheelEvent);
MouseArea {
id: mouseArea
anchors {
fill: parent
// not much point in finding exact values
leftMargin: root.fillWindowWidth ? -50 : 0
rightMargin: root.fillWindowWidth ? -50 : 0
topMargin: -root.extraVerticalMargin
bottomMargin: -root.extraVerticalMargin
}
Component.onCompleted: {
this.clicked.connect(root.clicked);
//this.entered.connect(root.entered);
//this.exited.connect(root.exited);
//this.pressed.connect(root.pressed);
this.released.connect(root.released);
//this.wheel.connect(root.wheel);
}
// for some reason MouseArea.pressed is both a prop and signal so connect doesn't work
onPressed: event => root.pressed(event);
// connecting to onwheel seems to implicitly accept it. undo that.
onWheel: event => {
event.accepted = false;
root.wheel(event);
}
}
}

1
quickshell/Mic.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M480-420q-41.92 0-70.96-29.04Q380-478.08 380-520v-240q0-41.92 29.04-70.96Q438.08-860 480-860q41.92 0 70.96 29.04Q580-801.92 580-760v240q0 41.92-29.04 70.96Q521.92-420 480-420Zm-30 290v-131.85q-99-11.31-164.5-84.92Q220-420.39 220-520h60q0 83 58.5 141.5T480-320q83 0 141.5-58.5T680-520h60q0 99.61-65.5 173.23Q609-273.16 510-261.85V-130h-60Z"/></svg>

After

Width:  |  Height:  |  Size: 463 B

45
quickshell/Player.qml Normal file
View File

@@ -0,0 +1,45 @@
pragma Singleton
import Quickshell
import Quickshell.Io
import QtQuick
import Quickshell.Services.Mpris
Singleton {
id: root
// property MprisPlayer trackedPlayer: null;
readonly property MprisPlayer activePlayer: PlayerController.activePlayer.identity === "Spotify"
? PlayerController.activePlayer
: null
readonly property string time: {
root.activePlayer.trackTitle
}
readonly property string artist: {
root.activePlayer.trackArtist
}
readonly property string timetime: {
Math.floor(root.activePlayer.position / 60) + ":" +
formatTwoDigits(Math.floor(root.activePlayer.position % 60))
}
readonly property string fulltime: {
Math.floor(root.activePlayer.length / 60) + ":" +
formatTwoDigits(Math.floor(root.activePlayer.length % 60))
}
function formatTwoDigits(num) {
return (num < 10 ? "0" : "") + num;
}
Timer {
// only emit the signal when the position is actually changing.
running: root.activePlayer.playbackState == MprisPlaybackState.Playing
// Make sure the position updates at least once per second.
interval: 1000
repeat: true
// emit the positionChanged signal every second.
onTriggered: root.activePlayer.positionChanged()
}
}

View File

@@ -0,0 +1,173 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQml.Models
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Services.Mpris
// import qs
Singleton {
id: root;
property MprisPlayer trackedPlayer: null;
property MprisPlayer activePlayer: findSpotify();
signal trackChanged(reverse: bool);
property bool __reverse: false;
property var activeTrack;
Instantiator {
model: Mpris.players;
Connections {
required property MprisPlayer modelData;
target: modelData;
Component.onCompleted: {
if (root.trackedPlayer == null || modelData.isPlaying) {
root.trackedPlayer = modelData;
}
}
Component.onDestruction: {
if (root.trackedPlayer == null || !root.trackedPlayer.isPlaying) {
for (const player of Mpris.players.values) {
if (player.playbackState.isPlaying) {
root.trackedPlayer = player;
break;
}
}
if (trackedPlayer == null && Mpris.players.values.length != 0) {
trackedPlayer = Mpris.players.values[0];
}
}
}
function onPlaybackStateChanged() {
if (root.trackedPlayer !== modelData) root.trackedPlayer = modelData;
}
}
}
Connections {
target: activePlayer
function onPostTrackChanged() {
root.updateTrack();
}
function onTrackArtUrlChanged() {
console.log("arturl:", activePlayer.trackArtUrl)
//root.updateTrack();
if (root.activePlayer.uniqueId == root.activeTrack.uniqueId && root.activePlayer.trackArtUrl != root.activeTrack.artUrl) {
// cantata likes to send cover updates *BEFORE* updating the track info.
// as such, art url changes shouldn't be able to break the reverse animation
const r = root.__reverse;
root.updateTrack();
root.__reverse = r;
}
}
}
onActivePlayerChanged: this.updateTrack();
function updateTrack() {
//console.log(`update: ${this.activePlayer?.trackTitle ?? ""} : ${this.activePlayer?.trackArtists}`)
this.activeTrack = {
uniqueId: this.activePlayer?.uniqueId ?? 0,
artUrl: this.activePlayer?.trackArtUrl ?? "",
title: this.activePlayer?.trackTitle || "Unknown Title",
artist: this.activePlayer?.trackArtist || "Unknown Artist",
album: this.activePlayer?.trackAlbum || "Unknown Album",
};
this.trackChanged(__reverse);
this.__reverse = false;
}
property bool isPlaying: this.activePlayer && this.activePlayer.isPlaying;
property bool canTogglePlaying: this.activePlayer?.canTogglePlaying ?? false;
function togglePlaying() {
if (this.canTogglePlaying) this.activePlayer.togglePlaying();
}
property bool canGoPrevious: this.activePlayer?.canGoPrevious ?? false;
function previous() {
if (this.canGoPrevious) {
this.__reverse = true;
this.activePlayer.previous();
}
}
property bool canGoNext: this.activePlayer?.canGoNext ?? false;
function next() {
if (this.canGoNext) {
this.__reverse = false;
this.activePlayer.next();
}
}
property bool canChangeVolume: this.activePlayer && this.activePlayer.volumeSupported && this.activePlayer.canControl;
property bool loopSupported: this.activePlayer && this.activePlayer.loopSupported && this.activePlayer.canControl;
property var loopState: this.activePlayer?.loopState ?? MprisLoopState.None;
function setLoopState(loopState: var) {
if (this.loopSupported) {
this.activePlayer.loopState = loopState;
}
}
property bool shuffleSupported: this.activePlayer && this.activePlayer.shuffleSupported && this.activePlayer.canControl;
property bool hasShuffle: this.activePlayer?.shuffle ?? false;
function setShuffle(shuffle: bool) {
if (this.shuffleSupported) {
this.activePlayer.shuffle = shuffle;
}
}
function setActivePlayer(player: MprisPlayer) {
const targetPlayer = player ?? Mpris.players[0];
console.log(`setactive: ${targetPlayer} from ${activePlayer}`)
if (targetPlayer && this.activePlayer) {
this.__reverse = Mpris.players.indexOf(targetPlayer) < Mpris.players.indexOf(this.activePlayer);
} else {
// always animate forward if going to null
this.__reverse = false;
}
this.trackedPlayer = targetPlayer;
}
function findSpotify(): MprisPlayer {
const players = Mpris.players
for (const player of players.values) {
if (player.identity == "Spotify") {
return player
}
}
console.log("");
}
IpcHandler {
target: "mpris"
function pauseAll(): void {
for (const player of Mpris.players.values) {
if (player.canPause) player.pause();
}
}
function playPause(): void { root.togglePlaying(); }
function previous(): void { root.previous(); }
function next(): void { root.next(); }
}
}

View File

@@ -0,0 +1,176 @@
// Reworked the PlayerController a bit
pragma Singleton
pragma ComponentBehavior: Bound
import QtQml.Models
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Services.Mpris
// import qs
Singleton {
id: root;
property Mpris mpris: Mpris;
property MprisPlayer activePlayer: findSpotify();
signal trackChanged(reverse: bool);
property bool __reverse: false;
property var activeTrack;
PersistentProperties {
id: persist
reloadableId: "MusicWidget";
property string lastActivePlayerIdentify: "";
onReloaded: {
// rightclickMenu.snapOpacity(widgetOpen ? 1.0 : 0.0)
}
}
Instantiator {
model: Mpris.players;
Connections {
required property MprisPlayer modelData;
target: modelData;
Component.onCompleted: {
if (root.trackedPlayer == null || modelData.isPlaying) {
root.trackedPlayer = modelData;
}
}
Component.onDestruction: {
if (root.trackedPlayer == null || !root.trackedPlayer.isPlaying) {
for (const player of Mpris.players.values) {
if (player.playbackState.isPlaying) {
root.trackedPlayer = player;
break;
}
}
if (trackedPlayer == null && Mpris.players.values.length != 0) {
trackedPlayer = Mpris.players.values[0];
}
}
}
function onPlaybackStateChanged() {
if (root.trackedPlayer !== modelData) root.trackedPlayer = modelData;
}
}
}
Connections {
target: activePlayer
function onPostTrackChanged() {
root.updateTrack();
}
function onTrackArtUrlChanged() {
console.log("arturl:", activePlayer.trackArtUrl)
//root.updateTrack();
if (root.activePlayer.uniqueId == root.activeTrack.uniqueId && root.activePlayer.trackArtUrl != root.activeTrack.artUrl) {
// cantata likes to send cover updates *BEFORE* updating the track info.
// as such, art url changes shouldn't be able to break the reverse animation
const r = root.__reverse;
root.updateTrack();
root.__reverse = r;
}
}
}
onActivePlayerChanged: this.updateTrack();
function updateTrack() {
//console.log(`update: ${this.activePlayer?.trackTitle ?? ""} : ${this.activePlayer?.trackArtists}`)
this.activeTrack = {
uniqueId: this.activePlayer?.uniqueId ?? 0,
artUrl: this.activePlayer?.trackArtUrl ?? "",
title: this.activePlayer?.trackTitle || "Unknown Title",
artist: this.activePlayer?.trackArtist || "Unknown Artist",
album: this.activePlayer?.trackAlbum || "Unknown Album",
};
this.trackChanged(__reverse);
this.__reverse = false;
}
property bool isPlaying: this.activePlayer && this.activePlayer.isPlaying;
property bool canTogglePlaying: this.activePlayer?.canTogglePlaying ?? false;
function togglePlaying() {
if (this.canTogglePlaying) this.activePlayer.togglePlaying();
}
property bool canGoPrevious: this.activePlayer?.canGoPrevious ?? false;
function previous() {
if (this.canGoPrevious) {
this.__reverse = true;
this.activePlayer.previous();
}
}
property bool canGoNext: this.activePlayer?.canGoNext ?? false;
function next() {
if (this.canGoNext) {
this.__reverse = false;
this.activePlayer.next();
}
}
property bool canChangeVolume: this.activePlayer && this.activePlayer.volumeSupported && this.activePlayer.canControl;
property bool loopSupported: this.activePlayer && this.activePlayer.loopSupported && this.activePlayer.canControl;
property var loopState: this.activePlayer?.loopState ?? MprisLoopState.None;
function setLoopState(loopState: var) {
if (this.loopSupported) {
this.activePlayer.loopState = loopState;
}
}
property bool shuffleSupported: this.activePlayer && this.activePlayer.shuffleSupported && this.activePlayer.canControl;
property bool hasShuffle: this.activePlayer?.shuffle ?? false;
function setShuffle(shuffle: bool) {
if (this.shuffleSupported) {
this.activePlayer.shuffle = shuffle;
}
}
function setActivePlayer(player: MprisPlayer) {
const targetPlayer = player ?? Mpris.players[0];
console.log(`setactive: ${targetPlayer} from ${activePlayer}`)
this.activePlayer = player;
}
function findSpotify(): MprisPlayer {
const players = Mpris.players
for (const player of players.values) {
if (player.identity == "Spotify") {
return player
}
}
console.log("");
}
IpcHandler {
target: "mpris"
function pauseAll(): void {
for (const player of Mpris.players.values) {
if (player.canPause) player.pause();
}
}
function playPause(): void { root.togglePlaying(); }
function previous(): void { root.previous(); }
function next(): void { root.next(); }
}
}

View File

@@ -0,0 +1,48 @@
import QtQml
import QtQuick
import Quickshell
import QtQuick.Layouts
PopupWindow {
property PlayerControllerV2 playerController: null;
id: audioPopup
anchor {
item: root
}
anchor.rect.x: root.width / 2 - width / 2
anchor.rect.y: root.height * 1.2
height: 350
width: 300
Rectangle {
anchors.fill: parent
color: "#919191"
ColumnLayout {
anchors.centerIn: parent
Item {
width: coverImg.width
height: coverImg.height
Image {
id: coverImg
anchors.fill: parent
source: Player.activePlayer.trackArtUrl;
width: 275
height: 275
fillMode: Image.PreserveAspectCrop
}
}
Text {
text: Player.activePlayer.trackTitle
color: "white"
font.pointSize: 10.75
}
Text {
text: Player.activePlayer.trackArtist
color: "white"
font.pointSize: 10.75
}
}
}
}

129
quickshell/PlayerText.qml Normal file
View File

@@ -0,0 +1,129 @@
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import QtQuick.Effects
// import playbutton.svg
Item {
id: root
Layout.fillHeight: true
implicitWidth: hi.width
visible: Player.activePlayer.canPlay()
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: event => {
audioPopup.visible = true;
}
onExited: event => {
audioPopup.visible = false;
}
}
Image {
source: Player.activePlayer.trackArtUrl;
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
layer.enabled: true
layer.effect: MultiEffect {
blur: 0.3
blurEnabled: true
}
}
// parent.aaaaa: false
RowLayout {
id: hi
Item {
implicitHeight: 30;
implicitWidth: 30;
IconImage {
implicitSize: 30;
source: "root:skip_next";
scale: -1
}
MouseArea {
anchors.fill: parent
onPressed: event => {
Player.activePlayer.previous();
}
}
}
Item {
implicitHeight: 30;
implicitWidth: 30;
IconImage {
implicitSize: 30;
source: !Player.activePlayer.isPlaying ? "root:playbutton.svg" : "root:pausebutton.svg";
}
MouseArea {
anchors.fill: parent
hoverEnabled: false
onPressed: event => {
Player.activePlayer.togglePlaying();
// console.debug("" + Player.activePlayer.)
}
}
// PopupAnchor {}
}
Item {
implicitHeight: 30;
implicitWidth: 30;
IconImage {
implicitSize: 30;
source: "root:skip_next";
}
MouseArea {
anchors.fill: parent
onPressed: event => {
Player.activePlayer.next();
}
}
}
}
PopupWindow {
id: audioPopup
color: "transparent"
anchor {
item: root
}
anchor.rect.x: root.width / 2 - width / 2
anchor.rect.y: root.height * 1.2
height: 350
width: 300
Rectangle {
anchors.fill: parent
color: "#919191"
ColumnLayout {
anchors.centerIn: parent
Item {
width: coverImg.width
height: coverImg.height
Image {
id: coverImg
anchors.fill: parent
source: Player.activePlayer.trackArtUrl;
width: 275
height: 275
fillMode: Image.PreserveAspectCrop
}
}
Text {
text: Player.activePlayer.trackTitle
color: "white"
font.pointSize: 10.75
}
Text {
text: Player.activePlayer.trackArtist
color: "white"
font.pointSize: 10.75
}
}
}
}
}

1
quickshell/Speaker.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M561.54-155.62v-62q86.54-27.53 139.42-100 52.89-72.46 52.89-163.38t-52.89-163.38q-52.88-72.47-139.42-100v-62q111.69 29.92 182 119.92 70.3 90 70.3 205.46 0 115.46-70.3 205.46-70.31 90-182 119.92ZM146.16-380v-200h148.46l171.53-171.53v543.06L294.62-380H146.16Zm415.38 46.15v-294.3q40.46 22 62.54 61.96 22.07 39.96 22.07 86.19 0 45.61-22.27 84.88-22.27 39.27-62.34 61.27Z"/></svg>

After

Width:  |  Height:  |  Size: 492 B

18
quickshell/Time.qml Normal file
View File

@@ -0,0 +1,18 @@
pragma Singleton
import Quickshell
import Quickshell.Io
import QtQuick
Singleton {
id: root
readonly property string time: {
Qt.formatDateTime(clock.date, "ddd d MMM [hh:mm]")
}
SystemClock {
id: clock
precision: SystemClock.Minutes
}
}

View File

@@ -0,0 +1,13 @@
import Quickshell
import QtQml
import QtQuick
Rectangle {
id: a
anchors {
top: parent.top
bottom: parent.bottom
}
width: 2
color: "#8d8d8d"
}

12
quickshell/WindowInfo.qml Normal file
View File

@@ -0,0 +1,12 @@
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import Quickshell.Hyprland
Item {
RowLayout {
}
}

42
quickshell/Workspaces.qml Normal file
View File

@@ -0,0 +1,42 @@
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import Quickshell.Hyprland
RowLayout {
id: root
spacing: 3
Repeater {
model: Hyprland.workspaces
delegate: Item {
required property int index
property HyprlandWorkspace index_workspace: Hyprland.workspaces.values[index]
width: 25
height: 30
MouseArea {
Rectangle {
id: reg
anchors.fill: parent
color: index_workspace.focused ? "#3B3B3B" : "#808080"
}
Layout.fillWidth: true
Text {
anchors.centerIn: parent
text: index_workspace.id
color: "#FFFFFF"
font.pointSize: 10.75
}
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onPressed: event => {
if (event.button === Qt.LeftButton) {
Hyprland.dispatch('workspace ' + index_workspace.id);
}
}
}
}
}
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M560-200v-560h160v560H560Zm-320 0v-560h160v560H240Z"/></svg>

After

Width:  |  Height:  |  Size: 176 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M320-200v-560l440 280-440 280Z"/></svg>

After

Width:  |  Height:  |  Size: 155 B

6
quickshell/shell.qml Normal file
View File

@@ -0,0 +1,6 @@
import Quickshell
import QtQuick
Scope {
Bar {}
}

1
quickshell/skip_next.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M660-240v-480h80v480h-80Zm-440 0v-480l360 240-360 240Z"/></svg>

After

Width:  |  Height:  |  Size: 179 B