Compare commits

..

6 commits

Author SHA1 Message Date
Benjamin Palko
11d0e4a838 try that out 2025-09-04 19:59:52 -04:00
Benjamin Palko
3074bcae38 remove menu stuff 2025-09-04 18:57:12 -04:00
Benjamin Palko
75f780753f bar margin 2025-09-04 17:26:10 -04:00
Benjamin Palko
37dfd1255a use window popup type to allow menu outside of parent window 2025-09-04 17:26:10 -04:00
Benjamin Palko
a40f7666dc rename pomodoro service 2025-09-04 17:25:04 -04:00
Benjamin Palko
4011f4b5c8 move bar to unified window setup 2025-09-04 17:25:04 -04:00
84 changed files with 999 additions and 1783 deletions

View file

@ -12,11 +12,13 @@ Run the shell
quickshell -c shell
```
Run app launcher
```shell
quickshell -c launcher
```
## Dependencies
- `quickshell`
- `qt6-wayland`
- `app2unit`
- `meson`
- `ninja`
- `python3`

View file

@ -2,12 +2,13 @@ import qs.config
import QtQuick
Text {
font.family: Styling.lucide.font.family
font.pixelSize: 16
color: Styling.theme.basecontent
color: Theme.palette.basecontent
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.fast
duration: 100
}
}
font.family: Theme.lucide.font.family
font.pixelSize: Dimensions.gpu.iconSize
font.bold: true
}

View file

@ -2,6 +2,8 @@ pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.constants
import qs.widgets
import QtQuick
import QtQuick.Layouts
import Quickshell.Services.Mpris
@ -14,43 +16,35 @@ Loader {
active: player != null
sourceComponent: ColumnLayout {
spacing: Styling.layout.spacing.xl
spacing: 12
implicitWidth: 800
StyledText {
id: text
Layout.alignment: Qt.AlignHCenter
font.pixelSize: Styling.typography.textSize.base
text: `${root.player.trackTitle} - ${root.player.trackArtist}`
font.pixelSize: Dimensions.mpris.fontSize
}
RowLayout {
Layout.alignment: Qt.AlignHCenter
StyledIconButton {
id: backButton
text: Styling.lucide.icons.skipBack
text: Icons.skipBack
onClicked: {
root.player.previous();
}
}
StyledIconButton {
id: playPauseButton
text: root.player.isPlaying ? Styling.lucide.icons.pause : Styling.lucide.icons.play
text: root.player.isPlaying ? Icons.pause : Icons.play
onClicked: {
root.player.isPlaying = !root.player.isPlaying;
}
}
StyledIconButton {
id: forwardButton
text: Styling.lucide.icons.skipForward
text: Icons.skipForward
onClicked: {
root.player.next();
}
@ -59,24 +53,21 @@ Loader {
StyledText {
Layout.alignment: Qt.AlignHCenter
font.pixelSize: Styling.typography.textSize.sm
text: {
function formatTime(num) {
return Math.floor(num).toString().padStart(2, "0");
}
return `${formatTime(root.player.position / 60)}:${formatTime(root.player.position % 60)} - ${formatTime(root.player.length / 60)}:${formatTime(root.player.length % 60)}`;
}
font.pixelSize: Dimensions.mpris.fontSize
}
StyledSlider {
Layout.fillWidth: true
from: 0
to: root.player.length ?? 0
value: root.player.position
implicitHeight: 6
Layout.fillWidth: true
onMoved: {
root.player.position = value;
}

View file

@ -1,11 +1,12 @@
import qs.config
import qs.components
import qs.constants
import qs.services
import qs.widgets
import QtQuick
import QtQuick.Layouts
RowLayout {
spacing: Styling.layout.spacing.xl
spacing: 8
Layout.alignment: Qt.AlignHCenter
@ -13,7 +14,7 @@ RowLayout {
id: previousPlayerButton
visible: Mpris.players.length > 1
text: Styling.lucide.icons.chevronLeft
text: Icons.chevronLeft
onClicked: {
Mpris.previousPlayer();
@ -21,7 +22,6 @@ RowLayout {
}
StyledText {
font.pixelSize: Styling.typography.textSize.xl
text: {
if (!Mpris.active) {
return "inactive";
@ -36,13 +36,14 @@ RowLayout {
}
return displayName;
}
font.pixelSize: 20
}
StyledIconButton {
id: nextPlayerButton
visible: Mpris.players.length > 1
text: Styling.lucide.icons.chevronRight
text: Icons.chevronRight
onClicked: {
Mpris.nextPlayer();

View file

@ -7,21 +7,19 @@ Button {
property alias border: rectangle.border
property alias radius: rectangle.radius
font.pixelSize: Styling.typography.textSize.base
font.family: Styling.typography.fontFamily
verticalPadding: 6
horizontalPadding: 8
font.pixelSize: 14
padding: 6
palette.button: hovered ? Styling.theme.primary : Styling.theme.base200
palette.button: hovered ? Theme.palette.primary : Theme.palette.base100
Behavior on palette.button {
ColorAnimation {
duration: Styling.animations.speed.normal
duration: 100
}
}
palette.buttonText: hoverEnabled && hovered ? Styling.theme.primarycontent : Styling.theme.basecontent
palette.buttonText: hoverEnabled && hovered ? Theme.palette.primarycontent : Theme.palette.basecontent
Behavior on palette.buttonText {
ColorAnimation {
duration: Styling.animations.speed.normal
duration: 100
}
}
@ -34,6 +32,6 @@ Button {
background: Rectangle {
id: rectangle
color: root.palette.button
radius: Styling.theme.radiusField
radius: 8
}
}

View file

@ -1,107 +0,0 @@
pragma ComponentBehavior: Bound
import qs.config
import QtQuick
import QtQuick.Controls
import Quickshell.Widgets
ComboBox {
id: control
palette.button: Styling.theme.base200
palette.buttonText: Styling.theme.basecontent
palette.highlight: Styling.theme.primary
palette.highlightedText: Styling.theme.primarycontent
palette.text: Styling.theme.basecontent
palette.window: Styling.theme.base200
implicitHeight: 40
delegate: ItemDelegate {
id: delegate
required property var model
required property int index
width: control.width
contentItem: StyledText {
text: delegate.model[control.textRole]
color: delegate.highlighted ? palette.highlightedText : palette.buttonText
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.fast
}
}
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
color: delegate.highlighted ? palette.highlight : palette.button
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.fast
}
}
}
highlighted: control.highlightedIndex === index
}
contentItem: StyledText {
leftPadding: 12
text: control.displayText
color: control.hovered || control.down ? palette.highlightedText : palette.buttonText
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.fast
}
}
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
background: Rectangle {
implicitWidth: 120
implicitHeight: 40
color: control.hovered || control.down ? palette.highlight : palette.button
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.fast
}
}
border.color: Styling.theme.base100
border.width: control.visualFocus ? 2 : 1
radius: Styling.theme.radiusSelector
}
popup: Popup {
palette: control.palette
y: control.height - 1
width: control.width
height: Math.min(contentItem.implicitHeight, control.Window.height - topMargin - bottomMargin)
padding: 1
contentItem: ClippingWrapperRectangle {
radius: Styling.theme.radiusField
ListView {
clip: true
implicitHeight: contentHeight + 2
model: control.popup.visible ? control.delegateModel : null
currentIndex: control.highlightedIndex
ScrollIndicator.vertical: ScrollIndicator {}
}
}
background: Rectangle {
color: palette.window
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.fast
}
}
radius: Styling.theme.radiusField
}
}
}

View file

@ -1,29 +1,11 @@
import qs.config
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Hyprland
import Quickshell.Widgets
Drawer {
id: control
dim: false
property bool focused: false
onVisibleChanged: {
focused = visible;
}
HyprlandFocusGrab {
active: control.focused
windows: [QsWindow.window]
onCleared: {
control.focused = false;
}
}
background: ClippingWrapperRectangle {
margin: 4
background: Rectangle {
Component.onCompleted: {
if (control.edge == Qt.TopEdge) {
radius = 8;
@ -38,24 +20,6 @@ Drawer {
topRightRadius = 8;
}
}
color: Styling.theme.base300
Rectangle {
Component.onCompleted: {
if (control.edge == Qt.TopEdge) {
radius = 8;
} else if (control.edge == Qt.LeftEdge) {
topRightRadius = 8;
bottomRightRadius = 8;
} else if (control.edge == Qt.RightEdge) {
topLeftRadius = 8;
bottomLeftRadius = 8;
} else if (control.edge == Qt.BottomEdge) {
topLeftRadius = 8;
topRightRadius = 8;
}
}
color: Styling.theme.base100
}
color: Theme.palette.base200
}
}

View file

@ -5,14 +5,19 @@ import QtQuick.Controls
RoundButton {
id: control
FontLoader {
id: loader
source: "../assets/lucide.woff"
}
property alias border: rect.border
property color color: hovered ? Styling.theme.primarycontent : Styling.theme.basecontent
property color color: hovered ? Theme.palette.primarycontent : Theme.palette.basecontent
property int rotation: 0
font.family: Styling.lucide.font.family
font.pixelSize: 16
radius: Styling.theme.radiusField
padding: 8
font.family: loader.font.family
font.pixelSize: 18
radius: 8
padding: 6
HoverHandler {
cursorShape: Qt.PointingHandCursor
@ -22,35 +27,34 @@ RoundButton {
id: icon
font: control.font
text: control.text
verticalAlignment: Text.AlignVCenter
color: control.color
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.normal
duration: 100
}
}
rotation: control.rotation
Behavior on rotation {
RotationAnimation {
duration: Styling.animations.speed.slow
easing.type: Easing.OutQuad
duration: 200
easing.type: Easing.InOutCubic
}
}
}
background: Rectangle {
id: rect
border.color: control.hovered ? Styling.theme.base300 : Styling.theme.base200
border.color: control.hovered ? Theme.palette.primary : Theme.palette.base100
Behavior on border.color {
ColorAnimation {
duration: Styling.animations.speed.normal
duration: 100
}
}
border.width: 0
color: control.hovered ? Styling.theme.primary : Styling.theme.base200
border.width: 2
color: control.hovered ? Theme.palette.primary : Theme.palette.base100
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.normal
duration: 100
}
}
radius: control.radius

View file

@ -1,17 +0,0 @@
import qs.config
import QtQuick
import Quickshell.Widgets
Image {
property alias radius: rectangle.radius
property alias skeletonColor: rectangle.color
ClippingRectangle {
id: rectangle
color: Styling.theme.base200
anchors.fill: parent
}
}

View file

@ -0,0 +1,16 @@
import qs.config
import QtQuick
import Quickshell.Widgets
WrapperRectangle {
id: root
margin: 8
radius: 8
color: Theme.palette.base100
Behavior on color {
ColorAnimation {
duration: 200
easing.type: Easing.InOutQuad
}
}
}

View file

@ -1,4 +1,3 @@
import qs.config
import QtQuick
import QtQuick.Controls
@ -15,7 +14,7 @@ ListView {
rebound: Transition {
NumberAnimation {
properties: "x,y"
duration: Styling.animations.speed.slow
duration: 400
easing.type: Easing.BezierSpline
easing.bezierCurve: [0.2, 0, 0, 1, 1, 1]
}

View file

@ -1,21 +0,0 @@
import qs.config
import QtQuick
import QtQuick.Controls
Pane {
id: pane
padding: 8
background: Rectangle {
color: "transparent"
border.width: Styling.theme.border
border.color: pane.hovered ? Styling.theme.accent : Styling.theme.basecontent
opacity: 0.33
Behavior on border.color {
ColorAnimation {
duration: Styling.animations.speed.fast
}
}
radius: Styling.theme.radiusBox
}
}

View file

@ -1,74 +0,0 @@
import qs.config
import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Wayland
PanelWindow {
id: window
default property alias content: contentItem.data
property alias background: background
required property string name
property bool canFocus: true
property bool focused: false
property int padding: 4
WlrLayershell.namespace: `lux-${name}`
WlrLayershell.layer: WlrLayer.Top
WlrLayershell.keyboardFocus: window.visible ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
onVisibleChanged: {
if (!canFocus)
return;
focused = visible;
}
HyprlandFocusGrab {
active: window.focused
windows: [window]
onCleared: {
if (!window.canFocus)
return;
window.focused = false;
}
}
color: "transparent"
Rectangle {
id: background
anchors.fill: parent
radius: Styling.theme.radiusBox
Behavior on radius {
NumberAnimation {
duration: Styling.animations.speed.normal
}
}
color: Styling.theme.base100
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.fast
}
}
Behavior on opacity {
NumberAnimation {
duration: Styling.animations.speed.fast
}
}
border.width: 2
border.color: Styling.theme.base300
Behavior on border.color {
ColorAnimation {
duration: Styling.animations.speed.fast
}
}
}
Item {
id: contentItem
anchors.centerIn: parent
implicitWidth: parent.width - 2 * window.padding
implicitHeight: parent.height - 2 * window.padding
}
}

View file

@ -6,87 +6,33 @@ import Quickshell.Hyprland
PopupWindow {
id: root
required property Component content
implicitWidth: background.width
implicitHeight: background.height
implicitWidth: contentItem.children.reduce((prev, child) => Math.max(prev, child.width), 0)
implicitHeight: contentItem.children.reduce((prev, child) => prev + child.height, 0)
color: "transparent"
contentItem.focus: visible
function open() {
visible = true;
}
function close() {
visible = false;
}
// WlrLayershell.layer: WlrLayer.Top
// WlrLayershell.keyboardFocus: root.visible ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
HyprlandFocusGrab {
id: grab
active: root.visible
windows: [root]
onCleared: {
background.state = "closed";
root.close();
}
}
function toggle() {
background.state = background.state == "opened" ? "closed" : "opened";
}
StyledWrapperRectangle {
Rectangle {
id: background
margin: 16
focus: true
onFocusChanged: {
if (!focus) {
grab.active = false;
}
}
Behavior on opacity {
NumberAnimation {
duration: Styling.animations.speed.normal
}
}
state: "closed"
states: [
State {
name: "closed"
PropertyChanges {
background {
opacity: 0
}
}
},
State {
name: "opened"
PropertyChanges {
background {
opacity: 1
}
}
}
]
transitions: [
Transition {
from: "closed"
to: "opened"
ScriptAction {
script: root.visible = true
}
},
Transition {
from: "opened"
to: "closed"
SequentialAnimation {
PauseAnimation {
duration: root.animationDuration
}
ScriptAction {
script: root.visible = false
}
}
}
]
Loader {
active: root.visible
sourceComponent: root.content
}
anchors.fill: parent
color: Theme.palette.base200
radius: 8
}
}

View file

@ -15,8 +15,8 @@ ProgressBar {
background: Rectangle {
implicitWidth: 200
implicitHeight: 6
color: Styling.theme.base100
radius: Styling.theme.radiusField
color: Theme.palette.base100
radius: 8
}
contentItem: Item {
@ -27,8 +27,8 @@ ProgressBar {
Rectangle {
width: control.visualPosition * parent.width
height: parent.height
radius: Styling.theme.radiusField
color: Styling.theme.primary
radius: 8
color: Theme.palette.primary
visible: !control.indeterminate
}
@ -41,14 +41,14 @@ ProgressBar {
Row {
Rectangle {
id: rect
color: Styling.theme.primary
color: Theme.palette.primary
width: 40
height: control.height
}
XAnimator on x {
from: control.width + rect.width
to: -rect.width
duration: Styling.animations.speed.verySlow
duration: 1000
loops: Animation.Infinite
running: control.indeterminate
}

View file

@ -1,12 +0,0 @@
import qs.config
import QtQuick
Rectangle {
radius: Styling.theme.radiusBox
color: Styling.theme.base200
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.normal
}
}
}

View file

@ -18,19 +18,19 @@ Slider {
implicitHeight: control.height
width: control.availableWidth
height: implicitHeight
radius: Styling.theme.radiusField
color: Styling.theme.base200
radius: 8
color: Theme.palette.base100
Rectangle {
width: control.visualPosition * parent.width
Behavior on width {
NumberAnimation {
duration: Styling.animations.speed.fast
duration: 75
}
}
height: parent.height
color: Styling.theme.primary
radius: Styling.theme.radiusField
color: Theme.palette.primary
radius: 8
}
}
handle: null

View file

@ -11,7 +11,7 @@ Switch {
text: control.text
font: control.font
opacity: enabled ? 1.0 : 0.3
color: Styling.theme.basecontent
color: Theme.palette.basecontent
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
@ -29,9 +29,9 @@ Switch {
implicitHeight: 24
x: control.width - width - control.rightPadding
y: parent.height / 2 - height / 2
radius: Styling.theme.radiusSelector
radius: 16
color: "transparent"
border.color: control.checked ? Styling.theme.primary : Styling.theme.basecontent
border.color: control.checked ? Theme.palette.primary : Theme.palette.basecontent
border.width: 2
Rectangle {
@ -40,15 +40,16 @@ Switch {
y: parent.height / 2 - height / 2
Behavior on x {
NumberAnimation {
duration: Styling.animations.speed.fast
duration: 100
}
}
width: parent.width / 2 - indicator.padding
height: parent.height - indicator.padding
radius: Styling.theme.radiusSelector
color: control.checked ? Styling.theme.primary : Styling.theme.basecontent
radius: 16
color: control.checked ? Theme.palette.primary : Theme.palette.basecontent
// border.color: control.checked ? (control.down ? "#17a81a" : "#21be2b") : "#999999"
}
}
background: Item {}
background: null
}

View file

@ -1,19 +0,0 @@
import QtQuick
import QtQuick.Controls
Container {
id: control
property alias orientation: view.orientation
contentItem: ListView {
id: view
model: control.contentModel
currentIndex: control.currentIndex
spacing: control.spacing
orientation: ListView.Horizontal
boundsBehavior: Flickable.StopAtBounds
}
background: Item {}
}

View file

@ -1,46 +0,0 @@
import qs.config
import QtQuick
import QtQuick.Controls
Button {
id: control
property alias radius: rectangle.radius
padding: 8
radius: Styling.theme.radiusField
contentItem: Text {
font.pixelSize: Styling.typography.textSize.base
font.family: Styling.typography.fontFamily
text: control.text
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: control.hovered ? Styling.theme.primarycontent : Styling.theme.basecontent
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.normal
}
}
}
background: Rectangle {
id: rectangle
color: control.hovered ? Styling.theme.primary : Styling.theme.base100
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.normal
}
}
opacity: control.checked || control.hovered ? 1.0 : 0.0
Behavior on opacity {
NumberAnimation {
duration: Styling.animations.speed.normal
}
}
}
HoverHandler {
cursorShape: Qt.PointingHandCursor
}
}

View file

@ -2,12 +2,9 @@ import qs.config
import QtQuick
Text {
font.family: Styling.typography.fontFamily
font.pixelSize: Styling.typography.textSize.base
color: Styling.theme.basecontent
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.fast
}
font.family: Theme.fontFamily
color: Theme.palette.basecontent
ColorAnimation on color {
duration: 100
}
}

View file

@ -1,9 +1,8 @@
import qs.config
import QtQuick
import QtQuick.Controls
TextField {
color: Styling.theme.basecontent
background: Item {}
color: Theme.palette.basecontent
background: null
}

View file

@ -9,13 +9,11 @@ ToolTip {
contentItem: Text {
text: control.text
font: control.font
color: Styling.theme.basecontent
color: Theme.palette.basecontent
}
background: Rectangle {
radius: Styling.theme.radiusBox
color: Styling.theme.base100
border.color: Styling.theme.base200
border.width: Styling.theme.border
radius: 8
color: Theme.palette.base200
}
}

View file

@ -0,0 +1,9 @@
import Quickshell
import Quickshell.Wayland
PanelWindow {
required property string name
WlrLayershell.namespace: `lux-${name}`
color: "transparent"
}

View file

@ -3,19 +3,12 @@ import QtQuick
import Quickshell.Widgets
WrapperRectangle {
margin: 8
radius: Styling.theme.radiusBox
color: Styling.theme.base100
radius: 8
color: Theme.palette.base300
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.fast
}
}
border.width: 2
border.color: Styling.theme.base100
Behavior on border.color {
ColorAnimation {
duration: Styling.animations.speed.fast
duration: 200
easing.type: Easing.InOutQuad
}
}
}

View file

@ -1,13 +0,0 @@
import qs.components
import qs.config
import QtQuick
StyledComboBox {
id: control
currentIndex: Theme.themes.indexOf(Theme.currentTheme)
model: Theme.themes
onActivated: index => {
Theme.currentTheme = Theme.themes[index];
}
}

View file

@ -1,14 +0,0 @@
import QtQuick
Image {
asynchronous: true
fillMode: Image.PreserveAspectCrop
sourceSize.width: parent.width
sourceSize.height: parent.height
Behavior on scale {
NumberAnimation {
duration: 200
}
}
}

View file

@ -1,65 +0,0 @@
pragma ComponentBehavior: Bound
import qs.config
import qs.services
import QtQuick
import Qt.labs.folderlistmodel 2.9
import Quickshell.Widgets
ListView {
id: list
orientation: ListView.Horizontal
clip: true
spacing: 8
snapMode: ListView.SnapToItem
implicitWidth: 160 * 3
implicitHeight: 90
model: FolderListModel {
nameFilters: ["*.jpg"]
folder: `file://${Paths.expandTilde(Config.wallpaper.directory)}`
showDirs: false
}
delegate: Item {
id: delegate
required property url fileUrl
required property int index
property bool hovered: ListView.isCurrentItem
implicitWidth: 160
implicitHeight: 90
Rectangle {
color: Styling.theme.base200
anchors.fill: parent
radius: 12
scale: delegate.hovered ? 1.0 : 0.9
Behavior on scale {
NumberAnimation {
duration: Styling.animations.veryFast
}
}
Image {
id: image
asynchronous: true
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
source: delegate.fileUrl
}
MouseArea {
anchors.fill: image
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onEntered: list.currentIndex = delegate.index
onClicked: WallpaperService.currentWallpaper = delegate.fileUrl
}
}
}
}

View file

@ -1,39 +1,9 @@
pragma Singleton
import Quickshell
import Quickshell.Io
Singleton {
id: root
readonly property alias powermenu: adapter.powermenu
readonly property alias wallpaper: adapter.wallpaper
FileView {
path: `${Paths.config}/shell.json`
watchChanges: true
onFileChanged: reload()
// onAdapterUpdated: writeAdapter()
JsonAdapter {
id: adapter
property var powermenu: PowerMenu {}
property var wallpaper: Wallpaper {}
}
}
component PowerMenu: JsonObject {
property list<PowerMenuItem> actions
}
component PowerMenuItem: JsonObject {
property string text
property string command
}
component Wallpaper: JsonObject {
property string directory
}
readonly property PowerMenu powermenu: PowerMenu {}
}

144
config/Dimensions.qml Normal file
View file

@ -0,0 +1,144 @@
pragma Singleton
import QtQuick
import Quickshell
Singleton {
id: root
property int radius: 8
property Bar bar: Bar {}
property Mpris mpris: Mpris {}
property Clock clock: Clock {}
property Pipewire pipewire: Pipewire {}
property Network network: Network {}
property Bluetooth bluetooth: Bluetooth {}
property Storage storage: Storage {}
property Memory memory: Memory {}
property Cpu cpu: Cpu {}
property Gpu gpu: Gpu {}
property Caffeine caffeine: Caffeine {}
property Notifications notifications: Notifications {}
property Workspace workspace: Workspace {}
property Tray tray: Tray {}
property TrayMenu trayMenu: TrayMenu {}
component Bar: QtObject {
property int spacing: 8
property int border: 2
property int height: 50
property int verticalMargins: 4
property int horizontalMargins: 8
property int verticalPadding: 2
property int horizontalPadding: 8
}
component Mpris: QtObject {
property int fontSize: 14
property int height: 30
property int horizontalPadding: 8
property int verticalPadding: 6
}
component Clock: QtObject {
property int fontSize: 14
property int height: 30
property int horizontalPadding: 8
property int verticalPadding: 6
}
component Pipewire: QtObject {
property int fontSize: 14
property int height: 30
property int horizontalPadding: 8
property int verticalPadding: 6
}
component Network: QtObject {
property int iconSize: 14
property int fontSize: 14
property int height: 30
property int horizontalPadding: 8
property int verticalPadding: 6
}
component Bluetooth: QtObject {
property int fontSize: 16
property int height: 30
property int horizontalPadding: 8
property int verticalPadding: 6
}
component Storage: QtObject {
property int iconSize: 14
property int fontSize: 14
property int height: 30
property int horizontalPadding: 8
property int verticalPadding: 6
}
component Memory: QtObject {
property int iconSize: 14
property int fontSize: 14
property int height: 30
property int horizontalPadding: 8
property int verticalPadding: 6
}
component Cpu: QtObject {
property int iconSize: 14
property int fontSize: 14
property int height: 30
property int horizontalPadding: 8
property int verticalPadding: 6
}
component Gpu: QtObject {
property int iconSize: 14
property int fontSize: 14
property int height: 30
property int horizontalPadding: 8
property int verticalPadding: 6
}
component Caffeine: QtObject {
property int fontSize: 16
property int height: 30
property int horizontalPadding: 8
property int verticalPadding: 6
}
component Notifications: QtObject {
property int fontSize: 16
property int height: 30
property int horizontalPadding: 8
property int verticalPadding: 6
}
component Workspace: QtObject {
property int spacing: 5
property int iconSize: 16
property int width: 30
property int height: 30
property int verticalPadding: 6
property int horizontalPadding: 7
}
component Tray: QtObject {
property int spacing: 5
property int iconSize: 18
property int width: 30
property int height: 30
property int verticalPadding: 6
property int horizontalPadding: 7
}
component TrayMenu: QtObject {
property int fontSize: 10
property int width: 30
property int height: 30
property int verticalPadding: 6
property int horizontalPadding: 7
}
}

View file

@ -1,45 +0,0 @@
pragma Singleton
import Quickshell
import Qt.labs.platform
Singleton {
id: root
readonly property url home: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]
readonly property url pictures: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
readonly property url data: `${StandardPaths.standardLocations(StandardPaths.GenericDataLocation)[0]}/lux`
readonly property url state: `${StandardPaths.standardLocations(StandardPaths.GenericStateLocation)[0]}/lux`
readonly property url cache: `${StandardPaths.standardLocations(StandardPaths.GenericCacheLocation)[0]}/lux`
readonly property url config: `${StandardPaths.standardLocations(StandardPaths.GenericConfigLocation)[0]}/lux`
function stringify(path: url): string {
let str = path.toString();
if (str.startsWith("root:/"))
str = `file://${Quickshell.shellDir}/${str.slice(6)}`;
else if (str.startsWith("/"))
str = `file://${str}`;
return new URL(str).pathname;
}
function expandTilde(path: string): string {
return strip(path.replace("~", stringify(root.home)));
}
function shortenHome(path: string): string {
return path.replace(strip(root.home), "~");
}
function strip(path: url): string {
return stringify(path).replace("file://", "");
}
function mkdir(path: url): void {
Quickshell.execDetached(["mkdir", "-p", strip(path)]);
}
function copy(from: url, to: url): void {
Quickshell.execDetached(["cp", strip(from), strip(to)]);
}
}

18
config/PowerMenu.qml Normal file
View file

@ -0,0 +1,18 @@
import Quickshell
PersistentProperties {
property list<var> actions: [
{
text: "󰍃 Logout",
command: "hyprctl dispatch exit"
},
{
text: "󰜉 Reboot",
command: "systemctl reboot"
},
{
text: " Shutdown",
command: "systemctl poweroff"
}
]
}

View file

@ -1,132 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
readonly property Animations animations: Animations {}
readonly property Typography typography: Typography {}
readonly property Layout layout: Layout {}
readonly property alias theme: theme
readonly property Lucide lucide: Lucide {}
component Animations: QtObject {
readonly property AnimationSpeed speed: AnimationSpeed {}
}
component AnimationSpeed: QtObject {
readonly property int veryFast: 50
readonly property int fast: 100
readonly property int normal: 200
readonly property int slow: 400
readonly property int verySlow: 1000
}
component Typography: QtObject {
readonly property string fontFamily: "JetBrainsMono Nerd Font"
readonly property FontSize textSize: FontSize {}
}
component FontSize: QtObject {
readonly property int sm: 12
readonly property int base: 14
readonly property int lg: 18
readonly property int xl: 24
}
component Layout: QtObject {
readonly property LayoutSpacing spacing: LayoutSpacing {}
}
component LayoutSpacing: QtObject {
readonly property int sm: 2
readonly property int base: 4
readonly property int lg: 8
readonly property int xl: 12
}
component Lucide: Item {
readonly property alias font: loader.font
readonly property LucideIcons icons: LucideIcons {}
FontLoader {
id: loader
source: "../assets/lucide.woff"
}
}
component LucideIcons: QtObject {
readonly property string activity: "\u{E038}"
readonly property string audioLines: "\u{E55F}"
readonly property string batteryCharging: "\u{E058}"
readonly property string batteryFull: "\u{E059}"
readonly property string batteryMedium: "\u{E05b}"
readonly property string batteryLow: "\u{E05a}"
readonly property string batteryWarning: "\u{E3b0}"
readonly property string bell: "\u{E05d}"
readonly property string bellRing: "\u{E224}"
readonly property string bluetooth: "\u{E060}"
readonly property string bluetoothConnected: "\u{E1b8}"
readonly property string brickWall: "\u{E586}"
readonly property string coffee: "\u{E09a}"
readonly property string chevronLeft: "\u{E072}"
readonly property string chevronRight: "\u{E073}"
readonly property string cpu: "\u{E0ad}"
readonly property string gpu: "\u{E66f}"
readonly property string hardDrive: "\u{E0f1}"
readonly property string layoutDashboard: "\u{E1C1}"
readonly property string memoryStick: "\u{E44a}"
readonly property string pause: "\u{E132}"
readonly property string play: "\u{E140}"
readonly property string search: "\u{E155}"
readonly property string skipBack: "\u{E163}"
readonly property string skipForward: "\u{E164}"
readonly property string square: "\u{E16B}"
readonly property string stop: "\u{E132}"
readonly property string swatchBook: "\u{E5A4}"
readonly property string wifiOff: "\u{E1af}"
readonly property string wifiLow: "\u{E5fd}"
readonly property string wifiHigh: "\u{E5fc}"
readonly property string wifi: "\u{E1ae}"
readonly property string triangle: "\u{E192}"
readonly property string triangleDashed: "\u{E642}"
}
FileView {
path: `${Paths.config}/themes/${Theme.currentTheme}.json`
watchChanges: true
onFileChanged: reload()
// when changes are made to properties in the adapter, save them
onAdapterUpdated: writeAdapter()
JsonAdapter {
id: theme
property color primary: "#605dff"
property color primarycontent: "#edf1fe"
property color secondary: "#f43098"
property color secondarycontent: "#f9e4f0"
property color accent: "#00d3bb"
property color accentcontent: "#084d49"
property color neutral: "#09090b"
property color neutralcontent: "#e4e4e7"
property color base100: "#1d232a"
property color base200: "#191e24"
property color base300: "#15191e"
property color basecontent: "#ecf9ff"
property color info: "#00bafe"
property color infocontent: "#042e49"
property color success: "#00d390"
property color successcontent: "#004c39"
property color warning: "#fcb700"
property color warningcontent: "#793205"
property color error: "#ff627d"
property color errorcontent: "#4d0218"
property int radiusSelector: 8
property int radiusField: 8
property int radiusBox: 8
property int border: 2
}
}
}

View file

@ -1,50 +1,39 @@
pragma Singleton
import QtQuick
import Qt.labs.folderlistmodel 2.9
import Quickshell
import Quickshell.Io
Singleton {
id: root
property alias themes: cache.themes
property alias currentTheme: cache.current
property int currentThemeIndex: themes.indexOf(currentTheme)
FolderListModel {
id: model
nameFilters: ["*.json"]
folder: `${Paths.config}/themes/`
showDirs: false
onCountChanged: {
const arr = [];
for (let i = 0; i < count; i++) {
arr.push(get(i, "fileName").replace(".json", ""));
}
root.themes = arr;
}
property var lucide: FontLoader {
source: "../assets/lucide.woff"
}
property string fontFamily: "JetBrainsMono Nerd Font"
property Palette palette: Palette {}
FileView {
path: `${Paths.cache}/theme.json`
component Palette: QtObject {
id: palette
watchChanges: true
onFileChanged: reload()
// when changes are made to properties in the adapter, save them
onAdapterUpdated: writeAdapter()
JsonAdapter {
id: cache
property string current: "dark"
property list<string> themes: ["dark"]
onThemesChanged: {
if (!themes.includes(current)) {
current = themes[0];
}
}
}
property color primary: "#1fb854"
property color primarycontent: "#000000"
property color secondary: "#1eb88e"
property color secondarycontent: "#000c07"
property color accent: "#1fb8ab"
property color accentcontent: "#010c0b"
property color neutral: "#19362d"
property color neutralcontent: "#cdd3d1"
property color base100: "#1b1717"
property color base200: "#161212"
property color base300: "#110d0d"
property color basecontent: "#cac9c9"
property color info: "#00b5ff"
property color infocontent: "#000000"
property color success: "#00a96e"
property color successcontent: "#000000"
property color warning: "#ffbe00"
property color warningcontent: "#000000"
property color error: "#ff5861"
property color errorcontent: "#000000"
}
}

36
constants/Icons.qml Normal file
View file

@ -0,0 +1,36 @@
pragma Singleton
import Quickshell
Singleton {
property string batteryCharging: "\u{E058}"
property string batteryFull: "\u{E059}"
property string batteryMedium: "\u{E05b}"
property string batteryLow: "\u{E05a}"
property string batteryWarning: "\u{E3b0}"
property string bell: "\u{E05d}"
property string bellRing: "\u{E224}"
property string bluetooth: "\u{E060}"
property string bluetoothConnected: "\u{E1b8}"
property string brickWall: "\u{E586}"
property string coffee: "\u{E09a}"
property string chevronLeft: "\u{E072}"
property string chevronRight: "\u{E073}"
property string cpu: "\u{E0ad}"
property string gpu: "\u{E66f}"
property string hardDrive: "\u{E0f1}"
property string memoryStick: "\u{E44a}"
property string pause: "\u{E132}"
property string play: "\u{E140}"
property string search: "\u{E155}"
property string skipBack: "\u{E163}"
property string skipForward: "\u{E164}"
property string stop: "\u{E132}"
property string square: "\u{E16B}"
property string wifiOff: "\u{E1af}"
property string wifiLow: "\u{E5fd}"
property string wifiHigh: "\u{E5fc}"
property string wifi: "\u{E1ae}"
property string triangle: "\u{E192}"
property string triangleDashed: "\u{E642}"
}

View file

@ -1,11 +1,9 @@
import "bar"
import "configuration"
import "drawers"
import "launcher"
import "pomodoro"
import "powermenu"
import "storybook"
import "wallpaper"
import QtQuick
import Quickshell
import Quickshell.Wayland
@ -18,23 +16,6 @@ Variants {
required property ShellScreen modelData
PanelWindow {
id: background
// visible: false
anchors.top: true
anchors.left: true
anchors.right: true
anchors.bottom: true
color: "transparent"
WlrLayershell.exclusionMode: ExclusionMode.Ignore
WlrLayershell.layer: WlrLayer.Background
Wallpaper {}
}
PanelWindow {
id: exclusionZone
@ -43,7 +24,7 @@ Variants {
anchors.right: true
implicitWidth: bar.width
implicitHeight: bar.height + bar.anchors.margins
implicitHeight: bar.height
color: "transparent"
}
@ -94,11 +75,14 @@ Variants {
}
}
}
Configuration {}
Launcher {}
Pomodoro {}
PowerMenu {}
Storybook {}
Storybook {
anchor.window: topWindow
anchor.rect.x: topWindow.width / 2 - width / 2
anchor.rect.y: topWindow.height / 4
}
Drawers {}
}
}

View file

@ -5,12 +5,6 @@ import Quickshell.Hyprland
Scope {
id: root
LuxShortcut {
name: 'configuration'
description: 'Open the configuration screen'
onPressed: Visibility.configuration = !Visibility.configuration
}
LuxShortcut {
name: 'launcher'
description: 'Open the application launcher'

View file

@ -14,24 +14,19 @@ StyledWrapperRectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 6
anchors.leftMargin: 10
anchors.rightMargin: 10
anchors.leftMargin: Dimensions.bar.horizontalMargins
anchors.rightMargin: Dimensions.bar.horizontalMargins
anchors.topMargin: Dimensions.bar.verticalMargins
anchors.bottomMargin: Dimensions.bar.verticalMargins
border.width: 3
border.color: Styling.theme.base200
margin: 4
color: Styling.theme.base100
margin: 6
RowLayout {
uniformCellSizes: true
RowLayout {
id: leftbar
spacing: Styling.layout.spacing.base
spacing: Dimensions.bar.spacing
SystemLogo {
implicitSize: 22
@ -47,7 +42,7 @@ StyledWrapperRectangle {
Layout.alignment: Qt.AlignHCenter
spacing: Styling.layout.spacing.base
spacing: Dimensions.bar.spacing
Mpris {}
}
@ -57,7 +52,7 @@ StyledWrapperRectangle {
Layout.alignment: Qt.AlignRight
spacing: Styling.layout.spacing.base
spacing: Dimensions.bar.spacing
Pywal {}

View file

@ -1,13 +1,13 @@
import qs.components
import qs.config
import qs.constants
import qs.services
StyledIconButton {
id: root
border.width: 2
border.color: Caffeine.enabled ? Styling.theme.secondary : root.hovered ? Styling.theme.primary : Styling.theme.base300
text: Styling.lucide.icons.coffee
border.color: Caffeine.enabled ? Theme.palette.secondary : root.hovered ? Theme.palette.primary : Theme.palette.base100
text: Icons.coffee
onClicked: {
Caffeine.toggle();

View file

@ -1,10 +1,19 @@
import qs.components
import qs.config
import qs.widgets
import Quickshell
StyledText {
StyledLabel {
StyledText {
id: text
font.pixelSize: Dimensions.clock.fontSize
text: ` ${Qt.formatDateTime(clock.date, "hh:mm:ss AP")}`
SystemClock {
id: clock
precision: SystemClock.Seconds
}
}
}

View file

@ -1,7 +1,9 @@
import qs.components
import qs.config
import qs.constants
import qs.services
import qs.utils
import qs.widgets
import QtQuick
import QtQuick.Layouts
@ -15,23 +17,30 @@ StyledButton {
}
contentItem: RowLayout {
id: row
spacing: 0
Ref {
service: SystemInfo
}
StyledText {
id: icon
LucideIcon {
text: Styling.lucide.icons.cpu
color: root.hovered ? Styling.theme.primarycontent : Styling.theme.basecontent
font.family: Theme.lucide.font.family
font.pixelSize: Dimensions.cpu.iconSize
font.bold: true
text: Icons.cpu
color: root.hovered ? Theme.palette.primarycontent : Theme.palette.basecontent
}
StyledText {
id: text
font.pixelSize: Dimensions.cpu.fontSize
text: ` ${(SystemInfo.cpuPerc * 100).toFixed().toString().padStart(2, "_")}%`
color: root.hovered ? Styling.theme.primarycontent : Styling.theme.basecontent
color: root.hovered ? Theme.palette.primarycontent : Theme.palette.basecontent
states: [
State {
name: "showTemp"

View file

@ -1,7 +1,9 @@
import qs.components
import qs.config
import qs.constants
import qs.services
import qs.utils
import qs.widgets
import QtQuick
import QtQuick.Layouts
@ -11,27 +13,34 @@ StyledButton {
property bool showTemp: false
onClicked: {
showTemp = !showTemp;
root.showTemp = !root.showTemp;
}
contentItem: RowLayout {
id: row
spacing: 0
Ref {
service: SystemInfo
}
StyledText {
id: icon
LucideIcon {
text: Styling.lucide.icons.gpu
color: root.hovered ? Styling.theme.primarycontent : Styling.theme.basecontent
font.family: Theme.lucide.font.family
font.pixelSize: Dimensions.gpu.iconSize
font.bold: true
text: Icons.gpu
color: root.hovered ? Theme.palette.primarycontent : Theme.palette.basecontent
}
StyledText {
id: text
font.pixelSize: Dimensions.gpu.fontSize
text: ` ${(SystemInfo.gpuPerc * 100).toFixed().toString().padStart(2, "_")}%`
color: root.hovered ? Styling.theme.primarycontent : Styling.theme.basecontent
color: root.hovered ? Theme.palette.primarycontent : Theme.palette.basecontent
states: [
State {
name: "temp"

View file

@ -1,21 +1,28 @@
import qs.components
import qs.config
import qs.constants
import qs.services
import qs.widgets
import qs.utils
import QtQuick
import QtQuick.Layouts
RowLayout {
StyledLabel {
RowLayout {
Ref {
service: SystemInfo
}
LucideIcon {
text: Styling.lucide.icons.memoryStick
StyledText {
font.family: Theme.lucide.font.family
font.pixelSize: Dimensions.memory.iconSize
font.bold: true
text: Icons.memoryStick
}
StyledText {
id: text
font.pixelSize: Dimensions.memory.fontSize
text: ` ${(SystemInfo.memPerc * 100).toFixed()}%`
}
}
}

View file

@ -1,26 +1,32 @@
import qs.components
import qs.config
import qs.constants
import qs.services
import qs.utils
import qs.widgets
import QtQuick
import QtQuick.Layouts
RowLayout {
StyledLabel {
RowLayout {
Ref {
service: NetworkService
}
LucideIcon {
StyledText {
id: icon
text: Styling.lucide.icons.wifiOff
font.family: Theme.lucide.font.family
font.pixelSize: Dimensions.network.iconSize
font.bold: true
text: Icons.wifiOff
states: [
State {
name: "high"
when: NetworkService.active?.strength > 50
PropertyChanges {
icon {
text: Styling.lucide.icons.wifi
text: Icons.wifi
}
}
},
@ -29,7 +35,7 @@ RowLayout {
when: NetworkService.active?.strength > 25
PropertyChanges {
icon {
text: Styling.lucide.icons.wifiHigh
text: Icons.wifiHigh
}
}
},
@ -38,7 +44,7 @@ RowLayout {
when: NetworkService.active?.strength > 0
PropertyChanges {
icon {
text: Styling.lucide.icons.wifiLow
text: Icons.wifiLow
}
}
}
@ -47,6 +53,8 @@ RowLayout {
StyledText {
id: text
font.pixelSize: Dimensions.network.fontSize
text: ` ${(NetworkService.active?.strength ?? 0).toFixed()}%`
}
}
}

View file

@ -28,7 +28,7 @@ StyledButton {
when: Pipewire.muted
PropertyChanges {
root {
palette.button: Styling.theme.error
palette.button: Theme.palette.error
}
}
}

View file

@ -1,5 +1,6 @@
import qs.components
import qs.config
import qs.constants
import QtQuick
import QtQuick.Layouts
import Quickshell.Services.UPower
@ -9,56 +10,50 @@ StyledButton {
property UPowerDevice laptopBattery: UPower.devices.values.find(device => device.isLaptopBattery) ?? null
property bool isCritical: laptopBattery?.percentage < 0.10
visible: laptopBattery
contentItem: RowLayout {
spacing: 4
LucideIcon {
Layout.alignment: Qt.AlignVCenter
color: {
if (root.isCritical) {
return Styling.theme.error;
return Theme.palette.error;
}
if (root.hovered) {
return Styling.theme.primarycontent;
return Theme.palette.primarycontent;
}
return Styling.theme.basecontent;
return Theme.palette.basecontent;
}
font.pixelSize: 16
text: {
if (root.laptopBattery?.state == UPowerDeviceState.Charging) {
return Styling.lucide.icons.batteryCharging;
return Icons.batteryCharging;
}
if (root.isCritical) {
return Styling.lucide.icons.batteryWarning;
return Icons.batteryWarning;
}
if (root.laptopBattery?.percentage < 0.33) {
return Styling.lucide.icons.batteryLow;
return Icons.batteryLow;
}
if (root.laptopBattery?.percentage < 0.66) {
return Styling.lucide.icons.batteryMedium;
return Icons.batteryMedium;
}
return Styling.lucide.icons.batteryFull;
return Icons.batteryFull;
}
}
StyledText {
Layout.alignment: Qt.AlignVCenter
color: {
if (root.isCritical) {
return Styling.theme.error;
return Theme.palette.error;
}
if (root.hovered) {
return Styling.theme.primarycontent;
return Theme.palette.primarycontent;
}
return Styling.theme.basecontent;
return Theme.palette.basecontent;
}
text: `${(root.laptopBattery?.percentage.toFixed(2) * 100)}%`
}
}
visible: laptopBattery
}

View file

@ -1,12 +1,12 @@
import qs.components
import qs.config
import qs.constants
import QtQuick
import Quickshell.Io
StyledIconButton {
id: clickable
text: Styling.lucide.icons.brickWall
text: Icons.brickWall
onClicked: {
process.running = true;

View file

@ -1,23 +1,30 @@
import qs.components
import qs.config
import qs.constants
import qs.services
import qs.utils
import qs.widgets
import QtQuick
import QtQuick.Layouts
RowLayout {
StyledLabel {
RowLayout {
Ref {
service: SystemInfo
}
StyledText {
id: icon
LucideIcon {
text: Styling.lucide.icons.hardDrive
font.family: Theme.lucide.font.family
font.pixelSize: Dimensions.storage.iconSize
font.bold: true
text: Icons.hardDrive
}
StyledText {
id: text
font.pixelSize: Dimensions.storage.fontSize
text: ` ${(SystemInfo.storagePerc * 100).toFixed()}%`
}
}
}

View file

@ -1,21 +1,21 @@
pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.widgets
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Bluetooth
import Quickshell.Widgets
StyledWrapperRectangle {
StyledLabel {
id: root
required property BluetoothDevice modelData
RowLayout {
id: row
spacing: Styling.layout.spacing.base
spacing: 8
Loader {
active: root.modelData?.icon != undefined

View file

@ -1,10 +1,10 @@
import qs.components
import qs.config
import qs.constants
StyledIconButton {
id: root
text: Styling.lucide.icons.bluetooth
text: Icons.bluetooth
onClicked: popup.toggle()

View file

@ -1,6 +1,8 @@
pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.widgets
import QtQuick
import QtQuick.Layouts
import Quickshell
@ -9,6 +11,10 @@ import Quickshell.Bluetooth
StyledPopupWindow {
id: root
backgroundColor: Theme.palette.base300
margins: 16
radius: 8
content: ColumnLayout {
spacing: 8
StyledWrapperRectangle {

View file

@ -2,20 +2,22 @@ pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.constants
import qs.widgets
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Bluetooth
import Quickshell.Widgets
StyledWrapperRectangle {
StyledLabel {
id: root
required property BluetoothDevice modelData
RowLayout {
id: row
spacing: Styling.layout.spacing.base
spacing: 8
Loader {
active: root.modelData?.icon != undefined
@ -32,9 +34,12 @@ StyledWrapperRectangle {
Loader {
active: root.modelData.batteryAvailable
sourceComponent: RowLayout {
LucideIcon {
StyledText {
id: icon
text: Styling.lucide.icons.batteryFull
font.family: Theme.lucide.font.family
font.pixelSize: Dimensions.cpu.iconSize
font.bold: true
text: Icons.batteryFull
states: [
State {
name: "full"
@ -45,7 +50,7 @@ StyledWrapperRectangle {
when: root.modelData.battery > 0.33
PropertyChanges {
icon {
text: Styling.lucide.icons.batteryFull
text: Icons.batteryFull
}
}
},
@ -54,7 +59,7 @@ StyledWrapperRectangle {
when: root.modelData.battery > 0.10
PropertyChanges {
icon {
text: Styling.lucide.icons.batteryFull
text: Icons.batteryFull
}
}
},
@ -63,8 +68,8 @@ StyledWrapperRectangle {
when: root.modelData.battery > 0.10
PropertyChanges {
icon {
text: Styling.lucide.icons.batteryWarning
color: Styling.theme.error
text: Icons.batteryWarning
color: Theme.palette.error
}
}
}
@ -76,7 +81,7 @@ StyledWrapperRectangle {
StyledButton {
Layout.alignment: Qt.AlignRight
text: 'Disconnect'
palette.button: hovered ? Styling.theme.error : Styling.theme.base200
palette.button: hovered ? Theme.palette.error : Theme.palette.base200
onClicked: {
if (root.modelData.state != BluetoothDeviceState.Connected) {

View file

@ -2,20 +2,21 @@ pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.widgets
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Bluetooth
import Quickshell.Widgets
StyledWrapperRectangle {
StyledLabel {
id: root
required property BluetoothDevice modelData
RowLayout {
id: row
spacing: Styling.layout.spacing.base
spacing: 8
Loader {
active: root.modelData?.icon != undefined
@ -47,7 +48,7 @@ StyledWrapperRectangle {
hoverEnabled: root.modelData.state == BluetoothDeviceState.Disconnected
text: 'Unpair'
palette.button: hovered ? Styling.theme.error : Styling.theme.base100
palette.button: hovered ? Theme.palette.error : Theme.palette.base100
onClicked: {
if (!hoverEnabled) {

View file

@ -1,5 +1,6 @@
import qs.components
import qs.config
import qs.constants
import QtQuick
import Quickshell.Hyprland
@ -8,7 +9,7 @@ StyledIconButton {
required property HyprlandWorkspace workspace
text: Styling.lucide.icons.triangle
text: Icons.triangle
font.bold: true
font.pixelSize: 17
padding: 8
@ -22,7 +23,7 @@ StyledIconButton {
PropertyChanges {
root {
rotation: 180
color: root.hovered ? Styling.theme.basecontent : Styling.theme.primary
color: root.hovered ? Theme.palette.basecontent : Theme.palette.primary
}
}
},
@ -31,9 +32,9 @@ StyledIconButton {
when: root.workspace.active
PropertyChanges {
root {
text: Styling.lucide.icons.triangleDashed
text: Icons.triangleDashed
rotation: 180
color: root.hovered ? Styling.theme.basecontent : Styling.theme.primary
color: root.hovered ? Theme.palette.basecontent : Theme.palette.primary
}
}
}

View file

@ -1,5 +1,6 @@
pragma ComponentBehavior: Bound
import qs.config
import QtQuick
import QtQuick.Layouts
import Quickshell.Hyprland
@ -7,7 +8,7 @@ import Quickshell.Hyprland
RowLayout {
id: root
spacing: 4
spacing: Dimensions.workspace.spacing
Repeater {

View file

@ -1,16 +1,18 @@
pragma ComponentBehavior: Bound
import qs.components
import qs.widgets
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
StyledWrapperRectangle {
StyledLabel {
id: root
required property var modelData
margin: 16
anchors.left: parent.left
anchors.right: parent.right

View file

@ -1,13 +1,19 @@
pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.services
import qs.widgets
import QtQuick
import QtQuick.Layouts
StyledPopupWindow {
id: root
backgroundColor: Theme.palette.base300
margins: 16
radius: 8
content: GridLayout {
columns: 2
@ -24,8 +30,9 @@ StyledPopupWindow {
onClicked: Notifications.clear()
}
StyledWrapperRectangle {
StyledLabel {
Layout.columnSpan: 2
color: Theme.palette.base200
StyledListView {
id: notifications

View file

@ -1,5 +1,5 @@
import qs.components
import qs.config
import qs.constants
import qs.services
import QtQuick
@ -10,13 +10,13 @@ StyledIconButton {
menu.toggle();
}
text: Notifications.hasNotifications ? Styling.lucide.icons.bell : Styling.lucide.icons.bellRing
text: Notifications.hasNotifications ? Icons.bell : Icons.bellRing
states: State {
when: Notifications.hasNotifications
PropertyChanges {
root {
text: Styling.lucide.icons.bellRing
text: Icons.bellRing
}
}
}

View file

@ -1,5 +1,6 @@
pragma ComponentBehavior: Bound
import qs.config
import QtQuick
import QtQuick.Layouts
import Quickshell.Services.SystemTray
@ -7,10 +8,10 @@ import Quickshell.Services.SystemTray
RowLayout {
id: root
spacing: 4
spacing: Dimensions.tray.spacing
Repeater {
model: SystemTray.items.values
model: SystemTray.items
Loader {
id: loader

View file

@ -5,11 +5,12 @@ import QtQuick
import Quickshell
import Quickshell.Services.SystemTray
import Quickshell.Widgets
import "menu/"
StyledIconButton {
id: root
required property SystemTrayItem trayItem
property SystemTrayItem trayItem
onClicked: menu.toggle()
@ -27,7 +28,7 @@ StyledIconButton {
}
}
TrayMenu {
Menu {
id: menu
anchor.item: root

View file

@ -1,49 +0,0 @@
pragma ComponentBehavior: Bound
import qs.components
import qs.config
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
StyledPopupWindow {
id: window
required property QsMenuOpener menuOpener
content: ColumnLayout {
spacing: 4
Repeater {
model: window.menuOpener.children.values
delegate: Loader {
id: loader
required property QsMenuEntry modelData
active: true
Component.onCompleted: {
console.log(modelData.text);
}
Layout.fillWidth: true
Layout.minimumWidth: 160
sourceComponent: modelData.isSeparator ? menuSeperator : menuItem
property Component menuSeperator: WrapperItem {
margin: 4
Rectangle {
implicitHeight: 2
color: Styling.theme.base200
}
}
property Component menuItem: StyledButton {
text: loader.modelData.text
onClicked: loader.modelData.triggered()
}
}
}
}
}

View file

@ -0,0 +1,43 @@
pragma ComponentBehavior: Bound
import qs.config
import qs.widgets
import QtQuick
import QtQuick.Layouts
import Quickshell
StyledPopupWindow {
id: window
backgroundColor: Theme.palette.base300
margins: 14
radius: 8
property QsMenuOpener menuOpener
content: ColumnLayout {
spacing: 8
Repeater {
model: window.menuOpener.children
delegate: Loader {
id: loader
required property QsMenuEntry modelData
active: true
Layout.fillWidth: true
Layout.minimumWidth: 160
sourceComponent: modelData.isSeparator ? menuSeperator : menuItem
property Component menuSeperator: Rectangle {
implicitHeight: 2
color: Theme.palette.base100
}
property Component menuItem: MenuItem {
menuEntry: loader.modelData
}
}
}
}
}

View file

@ -0,0 +1,12 @@
import qs.components
import Quickshell
StyledButton {
id: root
property QsMenuEntry menuEntry
text: root.menuEntry.text
onClicked: menuEntry.triggered()
}

View file

@ -1,88 +0,0 @@
import qs.components
import qs.config
import qs.services
import QtQuick
import QtQuick.Layouts
ColumnLayout {
anchors.fill: parent
spacing: Styling.layout.spacing.xl
StyledText {
text: "Speaker Settings"
}
StyledPane {
Layout.fillWidth: true
padding: 24
GridLayout {
Layout.fillWidth: true
columnSpacing: Styling.layout.spacing.xl
StyledText {
Layout.column: 1
Layout.row: 1
text: "Device"
}
StyledComboBox {
Layout.column: 2
Layout.row: 1
Layout.fillWidth: true
currentIndex: Pipewire.sinks.indexOf(Pipewire.sink)
model: Pipewire.sinks.map(sink => sink.nickname ?? sink.name)
onActivated: index => {
Pipewire.setSink(Pipewire.sinks[index]);
}
}
StyledText {
Layout.column: 1
Layout.row: 2
text: "Volume"
}
StyledSlider {
Layout.column: 2
Layout.row: 2
from: 0.0
to: 1.0
value: Pipewire.volume
onMoved: {
Pipewire.setVolume(value);
}
}
}
}
StyledText {
text: "Microphone Settings"
}
StyledPane {
Layout.fillWidth: true
padding: 24
GridLayout {
Layout.fillWidth: true
columnSpacing: Styling.layout.spacing.xl
StyledText {
Layout.column: 1
Layout.row: 2
text: "Microphones"
}
StyledComboBox {
Layout.column: 2
Layout.row: 2
Layout.fillWidth: true
currentIndex: Pipewire.sources.indexOf(Pipewire.source)
model: Pipewire.sources.map(source => source.nickname ?? source.name)
onActivated: index => {
Pipewire.setSource(Pipewire.sinks[index]);
}
}
}
}
}

View file

@ -1,128 +0,0 @@
pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.services
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Widgets
StyledPanelWindow {
id: window
name: "configuration"
visible: Visibility.configuration
implicitWidth: 1000
implicitHeight: 600
background.color: Styling.theme.base200
onFocusedChanged: {
Visibility.configuration = focused;
}
RowLayout {
anchors.fill: parent
StyledTabBar {
id: tabs
Layout.preferredWidth: 150
Layout.fillHeight: true
Layout.margins: 2
orientation: ListView.Vertical
spacing: 12
Repeater {
model: views.data
delegate: StyledTabButton {
id: tabButton
required property ConfigurationView modelData
anchors.left: parent.left
anchors.right: parent.right
required property int index
contentItem: RowLayout {
states: [
State {
when: tabButton.hovered
PropertyChanges {
tabIcon.color: Styling.theme.primarycontent
tabText.color: Styling.theme.primarycontent
}
}
]
LucideIcon {
id: tabIcon
text: tabButton.modelData.icon
font.pixelSize: Styling.typography.textSize.lg
}
StyledText {
id: tabText
text: tabButton.modelData.title
font.pixelSize: Styling.typography.textSize.lg
}
}
text: tabButton.modelData.title
onClicked: tabs.setCurrentIndex(index)
}
}
}
SwipeView {
id: view
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
orientation: Qt.Vertical
currentIndex: tabs.currentIndex
background: Rectangle {
color: Styling.theme.base100
radius: Styling.theme.radiusBox
}
Repeater {
model: views.data
delegate: ScrollView {
id: scrollView
required property ConfigurationView modelData
padding: 24
Loader {
anchors.fill: parent
active: scrollView.modelData.view
sourceComponent: scrollView.modelData.view
}
}
}
}
}
Item {
id: views
ConfigurationView {
icon: Styling.lucide.icons.audioLines
title: "Audio"
view: AudioView {}
}
ConfigurationView {
icon: Styling.lucide.icons.swatchBook
title: "Styling"
view: StylingView {}
}
}
component ConfigurationView: QtObject {
property string icon
property string title
property Component view
}
}

View file

@ -1,40 +0,0 @@
pragma ComponentBehavior: Bound
import qs.components
import qs.components.composite
import qs.config
import qs.services
import QtQuick
import QtQuick.Layouts
import Qt.labs.folderlistmodel 2.9
import Quickshell.Widgets
ColumnLayout {
StyledPane {
GridLayout {
columnSpacing: Styling.layout.spacing.xl
StyledText {
text: "Theme"
font.pixelSize: Styling.typography.textSize.lg
}
ThemeComboBox {}
}
}
// StyledPane {
// WallpaperList {}
// }
StyledPane {
padding: 2
ClippingWrapperRectangle {
radius: Styling.theme.radiusBox
color: "transparent"
WallpaperList {}
}
}
}

View file

@ -1,22 +1,16 @@
pragma ComponentBehavior: Bound
import qs.components
import qs.components.composite
import qs.services
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
StyledDrawer {
id: root
visible: Visibility.dashboard
onFocusedChanged: {
Visibility.dashboard = focused;
}
WrapperItem {
StyledWrapperRectangle {
margin: 32
ColumnLayout {
spacing: 8

View file

@ -4,6 +4,7 @@ import "items"
import "services"
import qs.components
import qs.config
import qs.widgets
import Quickshell
import QtQuick
import QtQuick.Controls
@ -31,7 +32,7 @@ StyledListView {
highlightResizeDuration: 0
highlight: Rectangle {
radius: 8
color: Styling.theme.primary
color: Theme.palette.primary
}
header: StyledText {

View file

@ -1,29 +1,40 @@
pragma ComponentBehavior: Bound
import "services"
import qs.config
import qs.components
import qs.constants
import qs.services
import Quickshell.Hyprland
import Quickshell.Wayland
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
StyledPanelWindow {
id: window
StyledWindow {
id: root
name: "launcher"
visible: Visibility.launcher
onVisibleChanged: {
if (!visible) {
list.currentIndex = 0;
search.clear();
}
Visibility.launcher = focused;
}
implicitWidth: rect.width
implicitHeight: rect.height
WrapperItem {
WlrLayershell.layer: WlrLayer.Top
WlrLayershell.keyboardFocus: root.visible ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
HyprlandFocusGrab {
active: root.visible
windows: [search]
onCleared: {
root.reset();
}
}
function reset() {
Visibility.launcher = false;
list.currentIndex = 0;
search.clear();
}
StyledWrapperRectangle {
id: rect
margin: 18
@ -34,13 +45,13 @@ StyledPanelWindow {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
color: Styling.theme.base200
margin: 4
RowLayout {
LucideIcon {
id: icon
Layout.leftMargin: 8
text: Styling.lucide.icons.search
text: Icons.search
}
StyledTextField {
@ -49,19 +60,19 @@ StyledPanelWindow {
Layout.fillWidth: true
implicitHeight: 40
cursorVisible: true
focus: window.visible
focus: root.visible
placeholderText: "Applications"
placeholderTextColor: "grey"
Keys.onEscapePressed: event => {
event.accepted = true;
Visibility.launcher = false;
root.reset();
}
Keys.onReturnPressed: event => {
event.accepted = true;
Apps.launch(list.currentItem.modelData);
Visibility.launcher = false;
root.reset();
}
Keys.onUpPressed: event => {
event.accepted = true;

View file

@ -42,7 +42,8 @@ Item {
Layout.alignment: Qt.AlignBottom
Layout.fillWidth: true
color: root.active ? Styling.theme.primarycontent : Styling.theme.basecontent
color: root.active ? Theme.palette.primarycontent : Theme.palette.basecontent
font.pixelSize: 14
font.bold: true
}
@ -51,8 +52,8 @@ Item {
Layout.alignment: Qt.AlignTop
Layout.fillWidth: true
color: root.active ? Styling.theme.primarycontent : Styling.theme.basecontent
font.pixelSize: Styling.typography.textSize.sm
color: root.active ? Theme.palette.primarycontent : Theme.palette.basecontent
font.pixelSize: 10
elide: Text.ElideRight
}
}

View file

@ -2,13 +2,15 @@ pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.constants
import qs.services
import qs.widgets
import Quickshell.Hyprland
import Quickshell.Wayland
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
StyledPanelWindow {
StyledWindow {
id: root
name: "pomodoro"
@ -16,11 +18,10 @@ StyledPanelWindow {
implicitWidth: rect.width
implicitHeight: rect.height
onFocusedChanged: {
Visibility.pomodoro = focused;
}
WlrLayershell.layer: WlrLayer.Top
WlrLayershell.keyboardFocus: root.visible ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
WrapperItem {
StyledWrapperRectangle {
id: rect
leftMargin: 48
@ -28,6 +29,14 @@ StyledPanelWindow {
topMargin: 24
bottomMargin: 24
HyprlandFocusGrab {
active: Visibility.pomodoro
windows: [root]
onCleared: {
Visibility.pomodoro = false;
}
}
ColumnLayout {
spacing: 22
@ -45,10 +54,10 @@ StyledPanelWindow {
Circle {
id: circle
radius: 150
borderColor: Styling.theme.base100
strokeColor: PomodoroService.state == "timer" ? Styling.theme.primary : Styling.theme.warning
borderColor: Theme.palette.base100
strokeColor: PomodoroService.state == "timer" ? Theme.palette.primary : Theme.palette.warning
strokeWidth: 12
fillColor: button.hovered ? Styling.theme.primary : "transparent"
fillColor: button.hovered ? Theme.palette.primary : "transparent"
percentage: (PomodoroService.state == "timer" ? (PomodoroService.initialTime - PomodoroService.remainingTime) : PomodoroService.remainingTime) / PomodoroService.initialTime % 1
}
@ -60,10 +69,10 @@ StyledPanelWindow {
radius: 9999
focus: root.visible
text: PomodoroService.running ? Styling.lucide.icons.square : Styling.lucide.icons.play
text: PomodoroService.running ? Icons.square : Icons.play
font.pixelSize: 48
background: Item {}
background: undefined
onClicked: {
PomodoroService.toggle();
}

View file

@ -3,12 +3,14 @@ pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.services
import qs.widgets
import Quickshell.Hyprland
import Quickshell.Io
import Quickshell.Wayland
import QtQuick
import QtQuick.Layouts
import Quickshell.Io
import Quickshell.Widgets
StyledPanelWindow {
StyledWindow {
id: root
name: "powermenu"
@ -16,18 +18,27 @@ StyledPanelWindow {
implicitWidth: rect.width
implicitHeight: rect.height
onFocusedChanged: {
Visibility.powermenu = focused;
}
WlrLayershell.layer: WlrLayer.Top
WlrLayershell.keyboardFocus: root.visible ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
Process {
id: process
}
WrapperItem {
StyledWrapperRectangle {
id: rect
color: Theme.palette.base300
margin: 14
radius: 8
HyprlandFocusGrab {
active: Visibility.powermenu
windows: [root]
onCleared: {
Visibility.powermenu = false;
}
}
StyledListView {
id: list
@ -58,7 +69,7 @@ StyledPanelWindow {
model: Config.powermenu.actions
spacing: Styling.layout.spacing.base
spacing: 8
implicitWidth: 220
implicitHeight: 185
@ -67,7 +78,7 @@ StyledPanelWindow {
highlightResizeDuration: 0
highlight: Rectangle {
radius: 8
color: Styling.theme.primary
color: Theme.palette.primary
}
onCurrentItemChanged: {
@ -94,9 +105,9 @@ StyledPanelWindow {
}
padding: 16
color: list.currentIndex == index ? Styling.theme.primarycontent : Styling.theme.basecontent
color: list.currentIndex == index ? Theme.palette.primarycontent : Theme.palette.basecontent
text: modelData.text
font.pixelSize: Styling.typography.textSize.lg
font.pixelSize: 18
font.bold: true
}
}

View file

@ -1,150 +0,0 @@
import qs.components
import qs.components.composite
import qs.config
import qs.services
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
GridLayout {
flow: GridLayout.TopToBottom
columns: 2
rows: 10
ColumnLayout {
StyledText {
text: "ToolTip"
font.pixelSize: 18
}
StyledPane {
Button {
id: toolTipButton
text: "Hello world!"
StyledToolTip {
visible: toolTipButton.hovered
text: qsTr("Save the active project")
}
}
}
}
ColumnLayout {
StyledText {
text: "ProgressBar"
font.pixelSize: 18
}
StyledPane {
StyledProgressBar {
id: progressBar
indeterminate: true
implicitHeight: 10
from: 0
to: 100
value: 50
}
}
}
ColumnLayout {
StyledText {
text: "ListView"
font.pixelSize: 18
}
StyledPane {
StyledWrapperRectangle {
border.color: Styling.theme.base100
border.width: 2
StyledListView {
implicitWidth: 200
implicitHeight: 100
model: 10
delegate: StyledText {
text: "Hello world!"
}
}
}
}
}
ColumnLayout {
StyledText {
text: "Mpris Player Selector"
font.pixelSize: 18
}
StyledPane {
MprisPlayerSelector {}
}
}
ColumnLayout {
StyledText {
text: "Mpris Controller"
font.pixelSize: 18
}
StyledPane {
MprisController {
player: Mpris.active ?? null
}
}
}
ColumnLayout {
StyledText {
text: "Drawer"
font.pixelSize: 18
}
StyledPane {
RowLayout {
Button {
text: "Top"
onClicked: {
drawer.x = root.width / 2 - drawer.width / 2;
drawer.y = 0;
drawer.edge = Qt.TopEdge;
drawer.open();
}
}
Button {
text: "Left"
onClicked: {
drawer.y = root.height / 2 - drawer.height / 2;
drawer.x = 0;
drawer.edge = Qt.LeftEdge;
drawer.open();
}
}
Button {
text: "Right"
onClicked: {
drawer.y = root.height / 2 - drawer.height / 2;
drawer.x = 0;
drawer.edge = Qt.RightEdge;
drawer.open();
}
}
Button {
text: "Bottom"
onClicked: {
drawer.x = root.width / 2 - drawer.width / 2;
drawer.y = 0;
drawer.edge = Qt.BottomEdge;
drawer.open();
}
}
}
}
}
StyledDrawer {
id: drawer
edge: Qt.TopEdge
width: 400
height: 200
Button {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: "Close"
onClicked: drawer.close()
}
}
}

View file

@ -1,53 +0,0 @@
import qs.components
import qs.config
import QtQuick
import QtQuick.Layouts
ColumnLayout {
spacing: Styling.layout.spacing.xl
ColumnLayout {
StyledText {
text: "Button"
font.pixelSize: 18
}
StyledPane {
StyledButton {
text: "Button"
}
}
}
ColumnLayout {
StyledText {
text: "Icon Button"
font.pixelSize: 18
}
StyledPane {
StyledIconButton {
text: Styling.lucide.icons.square
}
}
}
ColumnLayout {
StyledText {
text: "Slider"
font.pixelSize: 18
}
StyledPane {
StyledSlider {
id: slider
from: 0
to: 100
value: 50
}
}
}
component FieldElement: QtObject {
property string title
property Component component
}
}

View file

@ -1,22 +0,0 @@
import qs.components
import QtQuick
import QtQuick.Layouts
GridLayout {
flow: GridLayout.TopToBottom
columns: 2
rows: 10
ColumnLayout {
StyledText {
text: "Switch"
font.pixelSize: 18
}
StyledPane {
StyledSwitch {
text: "Enable"
}
}
}
}

View file

@ -2,72 +2,191 @@ pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.constants
import qs.services
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
StyledPanelWindow {
StyledPopupWindow {
id: root
name: "storybook"
visible: Visibility.storybook
implicitWidth: 500
implicitHeight: 600
background.color: Styling.theme.base200
GridLayout {
id: grid
onFocusedChanged: {
Visibility.storybook = focused;
}
flow: GridLayout.TopToBottom
columns: 2
rows: 10
StyledTabBar {
id: tabs
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: view.top
implicitHeight: 40
StyledTabButton {
text: "Fields"
onClicked: tabs.setCurrentIndex(0)
}
StyledTabButton {
text: "Selectors"
onClicked: tabs.setCurrentIndex(1)
}
StyledTabButton {
StyledText {
Layout.columnSpan: grid.columns
Layout.alignment: Qt.AlignHCenter
text: "Components"
onClicked: tabs.setCurrentIndex(2)
font.pixelSize: 24
font.bold: true
font.underline: true
bottomPadding: 24
}
ColumnLayout {
StyledText {
text: "Icon Button"
font.pixelSize: 18
}
StyledIconButton {
text: Icons.square
}
}
SwipeView {
id: view
anchors.top: tabs.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
currentIndex: tabs.currentIndex
background: Rectangle {
color: Styling.theme.base100
radius: Styling.theme.radiusBox
ColumnLayout {
StyledText {
text: "Switch"
font.pixelSize: 18
}
ScrollView {
padding: 36
Fields {}
StyledSwitch {
text: "Enable"
}
ScrollView {
padding: 36
Selectors {}
}
ScrollView {
padding: 36
Components {}
ColumnLayout {
StyledText {
text: "ToolTip"
font.pixelSize: 18
}
Button {
id: toolTipButton
text: "Hello world!"
StyledToolTip {
visible: toolTipButton.hovered
text: qsTr("Save the active project")
}
}
}
ColumnLayout {
StyledText {
text: "Slider"
font.pixelSize: 18
}
StyledSlider {
id: slider
from: 0
to: 100
value: 50
}
}
ColumnLayout {
StyledText {
text: "ProgressBar"
font.pixelSize: 18
}
StyledProgressBar {
id: progressBar
indeterminate: true
implicitHeight: 10
from: 0
to: 100
value: 50
}
}
ColumnLayout {
StyledText {
text: "ListView"
font.pixelSize: 18
}
StyledWrapperRectangle {
border.color: Theme.palette.base100
border.width: 2
StyledListView {
implicitWidth: 200
implicitHeight: 100
model: 10
delegate: StyledText {
text: "Hello world!"
}
}
}
}
ColumnLayout {
StyledText {
text: "Mpris Player Selector"
font.pixelSize: 18
}
MprisPlayerSelector {}
}
ColumnLayout {
StyledText {
text: "Mpris Controller"
font.pixelSize: 18
}
MprisController {
player: Mpris.active ?? null
}
}
ColumnLayout {
StyledText {
text: "Drawer"
font.pixelSize: 18
}
RowLayout {
Button {
text: "Top"
onClicked: {
drawer.x = root.width / 2 - drawer.width / 2;
drawer.y = 0;
drawer.edge = Qt.TopEdge;
drawer.open();
}
}
Button {
text: "Left"
onClicked: {
drawer.y = root.height / 2 - drawer.height / 2;
drawer.x = 0;
drawer.edge = Qt.LeftEdge;
drawer.open();
}
}
Button {
text: "Right"
onClicked: {
drawer.y = root.height / 2 - drawer.height / 2;
drawer.x = 0;
drawer.edge = Qt.RightEdge;
drawer.open();
}
}
Button {
text: "Bottom"
onClicked: {
drawer.x = root.width / 2 - drawer.width / 2;
drawer.y = 0;
drawer.edge = Qt.BottomEdge;
drawer.open();
}
}
}
}
}
StyledDrawer {
id: drawer
edge: Qt.TopEdge
width: 400
height: 200
Button {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: "Close"
onClicked: drawer.close()
}
}
}

View file

@ -1,35 +0,0 @@
import qs.services
import QtQuick
import QtQuick.Controls
StackView {
id: stack
property url wallpaper: WallpaperService.currentWallpaper
anchors.fill: parent
replaceEnter: Transition {
OpacityAnimator {
from: 0.0
to: 1.0
duration: 1000
}
}
replaceExit: Transition {
PauseAnimation {
duration: 1100
}
}
Component {
id: img
Image {}
}
Component.onCompleted: stack.replace(img, {
"source": stack.wallpaper
})
onWallpaperChanged: stack.replace(img, {
"source": stack.wallpaper
})
}

View file

@ -1,7 +1,7 @@
pragma Singleton
import Quickshell
import Quickshell.Wayland
import Quickshell.Io
Singleton {
@ -16,14 +16,16 @@ Singleton {
function toggle() {
if (properties.enabled) {
process.signal(888);
properties.enabled = false;
} else {
properties.enabled = true;
}
}
IdleInhibitor {
id: inhibitor
enabled: properties.enabled
Process {
id: process
running: properties.enabled
command: ["sh", "-c", "systemd-inhibit --what=idle --who=Caffeine --why='Caffeine module is active' --mode=block sleep inf"]
}
}

View file

@ -10,16 +10,13 @@ Singleton {
readonly property PwNode sink: Pipewire.defaultAudioSink
readonly property PwNode source: Pipewire.defaultAudioSource
readonly property list<PwNode> sinks: Pipewire.nodes.values.filter(node => node.audio != null && node.isSink && !node.isStream)
readonly property list<PwNode> sources: Pipewire.nodes.values.filter(node => node.audio != null && !node.isSink && !node.isStream)
readonly property bool muted: sink?.audio?.muted ?? false
readonly property real volume: sink?.audio?.volume ?? 0
function setVolume(volume: real): void {
if (sink?.ready && sink?.audio) {
sink.audio.muted = false;
sink.audio.volume = Math.min(volume, 1.0);
sink.audio.volume = volume;
}
}
@ -45,18 +42,6 @@ Singleton {
sink.audio.muted = !sink.audio.muted;
}
function setSink(node: PwNode) {
if (node.audio != null && node.isSink && !node.isStream) {
Pipewire.preferredDefaultAudioSink = node;
}
}
function setSource(node: PwNode) {
if (node.audio != null && !node.isSink && !node.isStream) {
Pipewire.preferredDefaultAudioSource = node;
}
}
PwObjectTracker {
objects: [Pipewire.defaultAudioSink, Pipewire.defaultAudioSource]
}

View file

@ -1,19 +1,27 @@
pragma Singleton
import qs.widgets
import Quickshell
Singleton {
property alias configuration: properties.configuration
property alias dashboard: properties.dashboard
property alias launcher: properties.launcher
property alias pomodoro: properties.pomodoro
property alias powermenu: properties.powermenu
property alias storybook: properties.storybook
property StyledPopupWindow activePopup
function togglePopup(popup: StyledPopupWindow) {
if (activePopup && popup != activePopup) {
activePopup.state = "";
}
popup.state = popup.state == "opened" ? "" : "opened";
activePopup = popup;
}
PersistentProperties {
id: properties
property bool configuration
property bool dashboard
property bool launcher
property bool pomodoro

View file

@ -1,27 +0,0 @@
pragma Singleton
import qs.config
import Quickshell
import Quickshell.Io
Singleton {
id: root
property alias currentWallpaper: properties.currentWallpaper
FileView {
path: `${Paths.cache}/wallpaper.json`
watchChanges: true
onFileChanged: reload()
// when changes are made to properties in the adapter, save them
onAdapterUpdated: writeAdapter()
JsonAdapter {
id: properties
property url currentWallpaper: ""
}
}
}

View file

@ -1,43 +0,0 @@
import QtQuick
import Quickshell.Io
Item {
id: root
required property string path
property bool recursive: true
property list<string> fileFilter: []
signal created(path: string)
signal modified(path: string)
signal deleted(path: string)
signal movedFrom(path: string)
signal movedTo(path: string)
Process {
running: true
command: ["bash", "-c", `inotifywait -m ${root.recursive ? "-r" : ""} ${root.path} -e modify,move,create,delete --format "%e-%w%f"`]
stderr: StdioCollector {
onStreamFinished: console.error(`DirectoryWatcher: ${this.text}`)
}
stdout: SplitParser {
splitMarker: "\n"
onRead: data => {
const [action, path] = data.split("-");
if (path.endsWith("~") || root.fileFilter.length > 0 && !root.fileFilter.some(filter => path.endsWith(filter))) {
return;
}
if (action.includes("CREATE")) {
root.created(path);
} else if (action.includes("MODIFY")) {
root.modified(path);
} else if (action.includes("DELETE")) {
root.deleted(path);
} else if (action.includes("MOVED_FROM")) {
root.movedFrom(path);
} else if (action.includes("MOVED_TO")) {
root.movedTo(path);
}
}
}
}
}

View file

@ -22,8 +22,8 @@ Item {
ShapePath {
id: fill
fillColor: Styling.theme.base100
strokeColor: Styling.theme.base200
fillColor: Theme.palette.base100
strokeColor: Theme.palette.base200
strokeWidth: 8
PathAngleArc {

View file

@ -0,0 +1,102 @@
import qs.services
import QtQuick
import Quickshell
import Quickshell.Widgets
PopupWindow {
id: root
property bool opened: false
property int animationDuration: 200
property alias margins: background.margin
property alias backgroundColor: background.color
property alias radius: background.radius
property alias state: background.state
required property Component content
color: "transparent"
function toggle() {
Visibility.togglePopup(this);
}
implicitWidth: background.width
Behavior on implicitWidth {
NumberAnimation {
duration: 100
}
}
implicitHeight: background.height
Behavior on implicitHeight {
NumberAnimation {
duration: 100
}
}
Timer {
id: timer
interval: 750
onTriggered: {
if (!root.visible) {
return;
}
root.toggle();
}
}
WrapperMouseArea {
hoverEnabled: true
onExited: {
timer.start();
}
onEntered: {
timer.stop();
}
WrapperRectangle {
id: background
opacity: 0
Behavior on opacity {
NumberAnimation {
duration: root.animationDuration
}
}
states: State {
name: "opened"
when: root.opened
PropertyChanges {
background {
opacity: 1
}
}
}
transitions: [
Transition {
from: ""
to: "opened"
ScriptAction {
script: root.visible = true
}
},
Transition {
from: "opened"
to: ""
SequentialAnimation {
PauseAnimation {
duration: root.animationDuration
}
ScriptAction {
script: root.visible = false
}
}
}
]
Loader {
active: root.visible
sourceComponent: root.content
}
}
}
}