Compare commits

..

82 commits

Author SHA1 Message Date
Benjamin Palko
618fc22e80 allow drawers to close on parent window focus lost 2025-11-10 11:54:25 -05:00
Benjamin Palko
3c3fe368bc simplify tray item 2025-10-28 20:57:58 -04:00
Benjamin Palko
fe8261f7af move theme types to Styling 2025-09-25 13:55:51 -04:00
Benjamin Palko
823dd66719 much better 2025-09-24 22:57:33 -04:00
Benjamin Palko
617931a115 initial load 2025-09-24 09:43:28 -04:00
Benjamin Palko
2aa72accda strip unused WallpaperService stuff 2025-09-23 23:01:33 -04:00
Benjamin Palko
6b9ecc5b3d add wallpaper config 2025-09-23 23:01:21 -04:00
Benjamin Palko
7ba6222105 powermenu config in shell json 2025-09-23 15:06:23 -04:00
Benjamin Palko
7935487295 reee 2025-09-23 14:13:24 -04:00
Benjamin Palko
d58144a853 styledimage 2025-09-23 13:19:38 -04:00
Benjamin Palko
2bfa0c189a wallpaper selection 2025-09-22 21:29:36 -04:00
Benjamin Palko
3d1816c0f1 wallpaper service 2025-09-20 23:08:57 -04:00
Benjamin Palko
9c074dc9e5 double import...fixed 2025-09-20 23:07:37 -04:00
Benjamin Palko
2d251c044d remove wallpaper view 2025-09-20 23:07:10 -04:00
Benjamin Palko
e2816bcb1e directory watcher 2025-09-20 21:21:30 -04:00
Benjamin Palko
d5a92eb19b remove, doesnt do anything 2025-09-18 21:16:15 -04:00
Benjamin Palko
8fe50936a0 kind of fix tabs for now
its fucked I dont want to deal with it right now
2025-09-18 21:04:08 -04:00
Benjamin Palko
450ff7a503 wallpapers WIP 2025-09-18 08:37:56 -04:00
Benjamin Palko
3a67bc5204 alias data 2025-09-17 17:39:03 -04:00
Benjamin Palko
0a445eaa08 remove padding and increase window size 2025-09-17 12:00:25 -04:00
Benjamin Palko
5e82fd906d formatting tabs 2025-09-17 11:57:21 -04:00
Benjamin Palko
338e81d3ad set default property on windowpanel for styling 2025-09-17 10:21:59 -04:00
Benjamin Palko
c22a8f796d move process, window cant take it atm 2025-09-17 10:21:42 -04:00
Benjamin Palko
ed6cd2c8d5 root panel window handles focus 2025-09-17 09:47:32 -04:00
Benjamin Palko
bd826c14ac refactor out theme object 2025-09-16 10:45:54 -04:00
Benjamin Palko
c03d24de15 create ThemeComboBox 2025-09-16 10:33:55 -04:00
Benjamin Palko
7a04cccf0c should use Styling 2025-09-16 10:33:42 -04:00
Benjamin Palko
fdf61a0e90 remove font family from theme 2025-09-16 10:32:19 -04:00
Benjamin Palko
37afb798bc move mpris player selector 2025-09-16 10:20:54 -04:00
Benjamin Palko
4007344d9d move mpris controller 2025-09-16 10:20:35 -04:00
Benjamin Palko
06bbd34b73 fuck that was easy 2025-09-16 08:59:56 -04:00
Benjamin Palko
c76f29345e tabbbss are still kinda fucked 2025-09-16 08:48:23 -04:00
Benjamin Palko
9d6a88aa43 add wayland and hyprland focus 2025-09-16 08:43:18 -04:00
Benjamin Palko
185121d0d7 style tab bar 2025-09-16 08:36:07 -04:00
Benjamin Palko
f687e17c94 limit volume 2025-09-15 22:05:02 -04:00
Benjamin Palko
b0d9342e1d forward control spacing 2025-09-15 22:04:46 -04:00
Benjamin Palko
1c30ea270f alias panel window background 2025-09-15 20:43:24 -04:00
Benjamin Palko
ebb66dee21 add audio volume slider 2025-09-15 20:37:53 -04:00
Benjamin Palko
141c64a0bb alias rectangle radius on tab button 2025-09-15 20:37:20 -04:00
Benjamin Palko
ad3a275c21 color animatinos 2025-09-15 16:16:35 -04:00
Benjamin Palko
1a8a14bf53 add more icons 2025-09-13 23:29:01 -04:00
Benjamin Palko
22cf6cc53e basic audio configurations 2025-09-13 22:53:40 -04:00
Benjamin Palko
8ba0567d28 vertical tabs on configuration 2025-09-11 23:57:12 -04:00
Benjamin Palko
83e9c6f08c override contentItem and alias orientation 2025-09-11 23:56:56 -04:00
Benjamin Palko
93b3a09a0a remove id 2025-09-11 23:41:14 -04:00
Benjamin Palko
9adae58589 swipeview 2025-09-11 23:41:07 -04:00
Benjamin Palko
f974911b1c color text on checked 2025-09-11 23:26:58 -04:00
Benjamin Palko
3306bb959c reduce default padding 2025-09-11 22:38:03 -04:00
Benjamin Palko
8104e3c099 wrap all items in pane 2025-09-11 17:05:14 -04:00
Benjamin Palko
2b6b9aee28 change border on tab button when active 2025-09-11 17:01:08 -04:00
Benjamin Palko
0ab37420a2 change pane border on hover 2025-09-11 17:00:43 -04:00
Benjamin Palko
01c2ea9044 add new dependencies 2025-09-10 12:02:37 -04:00
Benjamin Palko
fbc2a10b69 use quickshell idle inhib 2025-09-09 23:16:20 -04:00
Benjamin Palko
a10c2f0254 use pane on items 2025-09-08 10:56:07 -04:00
Benjamin Palko
162f8f6b6f tab button padding 2025-09-08 10:13:13 -04:00
Benjamin Palko
e180fee2a9 styled pane 2025-09-08 08:23:57 -04:00
Benjamin Palko
32167ef44e make storybook a tabbed window 2025-09-07 23:33:03 -04:00
Benjamin Palko
8aced615ce add theme selector to configurations 2025-09-07 22:32:25 -04:00
Benjamin Palko
47532bd626 add configuration menu 2025-09-07 13:25:02 -04:00
Benjamin Palko
25e313e31b clean up launcher, make it guuud 2025-09-07 12:52:53 -04:00
Benjamin Palko
ea86cc575d panel window contains background styling 2025-09-07 12:45:54 -04:00
Benjamin Palko
4bda51f02c panel window 2025-09-07 12:22:27 -04:00
Benjamin Palko
351fb82ac7 use wrapper rect 2025-09-07 12:21:33 -04:00
Benjamin Palko
112ed0d6de simplify StyledPopupWindow 2025-09-07 09:34:42 -04:00
Benjamin Palko
fdcaa77581 remove scuffed popup handling 2025-09-07 09:23:51 -04:00
Benjamin Palko
0405dc3414 rename to styled rectangle 2025-09-06 22:31:17 -04:00
Benjamin Palko
4e2a1874d1 delete styled popup 2025-09-06 22:28:06 -04:00
Benjamin Palko
96d1352666 move styledpopupwindow 2025-09-06 22:27:42 -04:00
Benjamin Palko
7022c3a9ae move bar to root window 2025-09-06 22:08:19 -04:00
Benjamin Palko
8c59137716 remove menu 2025-09-06 09:03:33 -04:00
Benjamin Palko
0c4d2dc597 rename pomodoro service 2025-09-06 09:01:38 -04:00
Benjamin Palko
af396bc2c5 layout, radius and border 2025-09-06 08:45:35 -04:00
Benjamin Palko
7de7ae19bb add typography 2025-09-05 22:41:21 -04:00
Benjamin Palko
205ad37e3e only watch theme files 2025-09-05 17:33:48 -04:00
Benjamin Palko
4375f6e13d move theme to styling 2025-09-05 17:30:09 -04:00
Benjamin Palko
467c9bc0e3 move lucide to Styling 2025-09-05 17:22:16 -04:00
Benjamin Palko
9fc91a92f7 add styling with animation speed 2025-09-05 15:48:24 -04:00
Benjamin Palko
f7e8fb7720 adjust theme on components 2025-09-05 15:15:17 -04:00
Benjamin Palko
a44b6f5e44 implement theme file storage 2025-09-05 13:12:40 -04:00
Benjamin Palko
c53f0c2c41 migrate themes to config dir 2025-09-05 12:12:11 -04:00
Benjamin Palko
a12b36c188 paths 2025-09-04 20:01:36 -04:00
Benjamin Palko
16e5059c7a empty item 2025-09-04 17:26:00 -04:00
84 changed files with 1783 additions and 999 deletions

View file

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

View file

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

View file

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

View file

@ -0,0 +1,107 @@
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,11 +1,29 @@
import qs.config
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Hyprland
import Quickshell.Widgets
Drawer {
id: control
dim: false
background: Rectangle {
property bool focused: false
onVisibleChanged: {
focused = visible;
}
HyprlandFocusGrab {
active: control.focused
windows: [QsWindow.window]
onCleared: {
control.focused = false;
}
}
background: ClippingWrapperRectangle {
margin: 4
Component.onCompleted: {
if (control.edge == Qt.TopEdge) {
radius = 8;
@ -20,6 +38,24 @@ Drawer {
topRightRadius = 8;
}
}
color: Theme.palette.base200
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
}
}
}

View file

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

View file

@ -0,0 +1,17 @@
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

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

21
components/StyledPane.qml Normal file
View file

@ -0,0 +1,21 @@
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

@ -0,0 +1,74 @@
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,33 +6,87 @@ import Quickshell.Hyprland
PopupWindow {
id: root
implicitWidth: contentItem.children.reduce((prev, child) => Math.max(prev, child.width), 0)
implicitHeight: contentItem.children.reduce((prev, child) => prev + child.height, 0)
required property Component content
implicitWidth: background.width
implicitHeight: background.height
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: {
root.close();
background.state = "closed";
}
}
Rectangle {
function toggle() {
background.state = background.state == "opened" ? "closed" : "opened";
}
StyledWrapperRectangle {
id: background
anchors.fill: parent
color: Theme.palette.base200
radius: 8
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
}
}
}

View file

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

View file

@ -0,0 +1,12 @@
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: 8
color: Theme.palette.base100
radius: Styling.theme.radiusField
color: Styling.theme.base200
Rectangle {
width: control.visualPosition * parent.width
Behavior on width {
NumberAnimation {
duration: 75
duration: Styling.animations.speed.fast
}
}
height: parent.height
color: Theme.palette.primary
radius: 8
color: Styling.theme.primary
radius: Styling.theme.radiusField
}
}
handle: null

View file

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

View file

@ -0,0 +1,19 @@
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

@ -0,0 +1,46 @@
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,9 +2,12 @@ import qs.config
import QtQuick
Text {
font.family: Theme.fontFamily
color: Theme.palette.basecontent
ColorAnimation on color {
duration: 100
font.family: Styling.typography.fontFamily
font.pixelSize: Styling.typography.textSize.base
color: Styling.theme.basecontent
Behavior on color {
ColorAnimation {
duration: Styling.animations.speed.fast
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -2,8 +2,6 @@ pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.constants
import qs.widgets
import QtQuick
import QtQuick.Layouts
import Quickshell.Services.Mpris
@ -16,35 +14,43 @@ Loader {
active: player != null
sourceComponent: ColumnLayout {
spacing: 12
spacing: Styling.layout.spacing.xl
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: Icons.skipBack
text: Styling.lucide.icons.skipBack
onClicked: {
root.player.previous();
}
}
StyledIconButton {
id: playPauseButton
text: root.player.isPlaying ? Icons.pause : Icons.play
text: root.player.isPlaying ? Styling.lucide.icons.pause : Styling.lucide.icons.play
onClicked: {
root.player.isPlaying = !root.player.isPlaying;
}
}
StyledIconButton {
id: forwardButton
text: Icons.skipForward
text: Styling.lucide.icons.skipForward
onClicked: {
root.player.next();
}
@ -53,21 +59,24 @@ 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,12 +1,11 @@
import qs.config
import qs.components
import qs.constants
import qs.services
import qs.widgets
import QtQuick
import QtQuick.Layouts
RowLayout {
spacing: 8
spacing: Styling.layout.spacing.xl
Layout.alignment: Qt.AlignHCenter
@ -14,7 +13,7 @@ RowLayout {
id: previousPlayerButton
visible: Mpris.players.length > 1
text: Icons.chevronLeft
text: Styling.lucide.icons.chevronLeft
onClicked: {
Mpris.previousPlayer();
@ -22,6 +21,7 @@ RowLayout {
}
StyledText {
font.pixelSize: Styling.typography.textSize.xl
text: {
if (!Mpris.active) {
return "inactive";
@ -36,14 +36,13 @@ RowLayout {
}
return displayName;
}
font.pixelSize: 20
}
StyledIconButton {
id: nextPlayerButton
visible: Mpris.players.length > 1
text: Icons.chevronRight
text: Styling.lucide.icons.chevronRight
onClicked: {
Mpris.nextPlayer();

View file

@ -0,0 +1,13 @@
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

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

View file

@ -0,0 +1,65 @@
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,9 +1,39 @@
pragma Singleton
import Quickshell
import Quickshell.Io
Singleton {
id: root
readonly property PowerMenu powermenu: PowerMenu {}
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
}
}

View file

@ -1,144 +0,0 @@
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
}
}

45
config/Paths.qml Normal file
View file

@ -0,0 +1,45 @@
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)]);
}
}

View file

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

132
config/Styling.qml Normal file
View file

@ -0,0 +1,132 @@
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,39 +1,50 @@
pragma Singleton
import QtQuick
import Qt.labs.folderlistmodel 2.9
import Quickshell
import Quickshell.Io
Singleton {
id: root
property var lucide: FontLoader {
source: "../assets/lucide.woff"
}
property string fontFamily: "JetBrainsMono Nerd Font"
property Palette palette: Palette {}
property alias themes: cache.themes
property alias currentTheme: cache.current
property int currentThemeIndex: themes.indexOf(currentTheme)
component Palette: QtObject {
id: palette
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 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"
FileView {
path: `${Paths.cache}/theme.json`
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];
}
}
}
}
}

View file

@ -1,36 +0,0 @@
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,9 +1,11 @@
import "bar"
import "configuration"
import "drawers"
import "launcher"
import "pomodoro"
import "powermenu"
import "storybook"
import "wallpaper"
import QtQuick
import Quickshell
import Quickshell.Wayland
@ -16,6 +18,23 @@ 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
@ -24,7 +43,7 @@ Variants {
anchors.right: true
implicitWidth: bar.width
implicitHeight: bar.height
implicitHeight: bar.height + bar.anchors.margins
color: "transparent"
}
@ -75,14 +94,11 @@ Variants {
}
}
}
Configuration {}
Launcher {}
Pomodoro {}
PowerMenu {}
Storybook {
anchor.window: topWindow
anchor.rect.x: topWindow.width / 2 - width / 2
anchor.rect.y: topWindow.height / 4
}
Storybook {}
Drawers {}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,5 @@
import qs.components
import qs.config
import qs.constants
import QtQuick
import QtQuick.Layouts
import Quickshell.Services.UPower
@ -10,50 +9,56 @@ 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 Theme.palette.error;
return Styling.theme.error;
}
if (root.hovered) {
return Theme.palette.primarycontent;
return Styling.theme.primarycontent;
}
return Theme.palette.basecontent;
return Styling.theme.basecontent;
}
font.pixelSize: 16
text: {
if (root.laptopBattery?.state == UPowerDeviceState.Charging) {
return Icons.batteryCharging;
return Styling.lucide.icons.batteryCharging;
}
if (root.isCritical) {
return Icons.batteryWarning;
return Styling.lucide.icons.batteryWarning;
}
if (root.laptopBattery?.percentage < 0.33) {
return Icons.batteryLow;
return Styling.lucide.icons.batteryLow;
}
if (root.laptopBattery?.percentage < 0.66) {
return Icons.batteryMedium;
return Styling.lucide.icons.batteryMedium;
}
return Icons.batteryFull;
return Styling.lucide.icons.batteryFull;
}
}
StyledText {
Layout.alignment: Qt.AlignVCenter
color: {
if (root.isCritical) {
return Theme.palette.error;
return Styling.theme.error;
}
if (root.hovered) {
return Theme.palette.primarycontent;
return Styling.theme.primarycontent;
}
return Theme.palette.basecontent;
return Styling.theme.basecontent;
}
text: `${(root.laptopBattery?.percentage.toFixed(2) * 100)}%`
}
}
visible: laptopBattery
}

View file

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

View file

@ -1,30 +1,23 @@
import qs.components
import qs.config
import qs.constants
import qs.services
import qs.utils
import qs.widgets
import QtQuick
import QtQuick.Layouts
StyledLabel {
RowLayout {
Ref {
service: SystemInfo
}
StyledText {
id: icon
font.family: Theme.lucide.font.family
font.pixelSize: Dimensions.storage.iconSize
font.bold: true
text: Icons.hardDrive
LucideIcon {
text: Styling.lucide.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.widgets
import qs.config
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Bluetooth
import Quickshell.Widgets
StyledLabel {
StyledWrapperRectangle {
id: root
required property BluetoothDevice modelData
RowLayout {
id: row
spacing: 8
spacing: Styling.layout.spacing.base
Loader {
active: root.modelData?.icon != undefined

View file

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

View file

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

View file

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

View file

@ -2,21 +2,20 @@ 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
StyledLabel {
StyledWrapperRectangle {
id: root
required property BluetoothDevice modelData
RowLayout {
id: row
spacing: 8
spacing: Styling.layout.spacing.base
Loader {
active: root.modelData?.icon != undefined
@ -48,7 +47,7 @@ StyledLabel {
hoverEnabled: root.modelData.state == BluetoothDeviceState.Disconnected
text: 'Unpair'
palette.button: hovered ? Theme.palette.error : Theme.palette.base100
palette.button: hovered ? Styling.theme.error : Styling.theme.base100
onClicked: {
if (!hoverEnabled) {

View file

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

View file

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

View file

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

View file

@ -1,19 +1,13 @@
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
@ -30,9 +24,8 @@ StyledPopupWindow {
onClicked: Notifications.clear()
}
StyledLabel {
StyledWrapperRectangle {
Layout.columnSpan: 2
color: Theme.palette.base200
StyledListView {
id: notifications

View file

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

View file

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

View file

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

View file

@ -0,0 +1,49 @@
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

@ -1,43 +0,0 @@
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

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

View file

@ -0,0 +1,88 @@
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

@ -0,0 +1,128 @@
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

@ -0,0 +1,40 @@
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,16 +1,22 @@
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
StyledWrapperRectangle {
onFocusedChanged: {
Visibility.dashboard = focused;
}
WrapperItem {
margin: 32
ColumnLayout {
spacing: 8

View file

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

View file

@ -1,40 +1,29 @@
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
StyledWindow {
id: root
StyledPanelWindow {
id: window
name: "launcher"
visible: Visibility.launcher
implicitWidth: rect.width
implicitHeight: rect.height
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;
onVisibleChanged: {
if (!visible) {
list.currentIndex = 0;
search.clear();
}
Visibility.launcher = focused;
}
implicitWidth: rect.width
implicitHeight: rect.height
StyledWrapperRectangle {
WrapperItem {
id: rect
margin: 18
@ -45,13 +34,13 @@ StyledWindow {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
margin: 4
color: Styling.theme.base200
RowLayout {
LucideIcon {
id: icon
Layout.leftMargin: 8
text: Icons.search
text: Styling.lucide.icons.search
}
StyledTextField {
@ -60,19 +49,19 @@ StyledWindow {
Layout.fillWidth: true
implicitHeight: 40
cursorVisible: true
focus: root.visible
focus: window.visible
placeholderText: "Applications"
placeholderTextColor: "grey"
Keys.onEscapePressed: event => {
event.accepted = true;
root.reset();
Visibility.launcher = false;
}
Keys.onReturnPressed: event => {
event.accepted = true;
Apps.launch(list.currentItem.modelData);
root.reset();
Visibility.launcher = false;
}
Keys.onUpPressed: event => {
event.accepted = true;

View file

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

View file

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

View file

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

View file

@ -0,0 +1,150 @@
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

@ -0,0 +1,53 @@
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

@ -0,0 +1,22 @@
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,191 +2,72 @@ pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.constants
import qs.services
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
StyledPopupWindow {
StyledPanelWindow {
id: root
name: "storybook"
visible: Visibility.storybook
implicitWidth: 500
implicitHeight: 600
GridLayout {
id: grid
background.color: Styling.theme.base200
flow: GridLayout.TopToBottom
columns: 2
rows: 10
onFocusedChanged: {
Visibility.storybook = focused;
}
StyledText {
Layout.columnSpan: grid.columns
Layout.alignment: Qt.AlignHCenter
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 {
text: "Components"
font.pixelSize: 24
font.bold: true
font.underline: true
bottomPadding: 24
}
ColumnLayout {
StyledText {
text: "Icon Button"
font.pixelSize: 18
}
StyledIconButton {
text: Icons.square
onClicked: tabs.setCurrentIndex(2)
}
}
ColumnLayout {
StyledText {
text: "Switch"
font.pixelSize: 18
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
}
StyledSwitch {
text: "Enable"
ScrollView {
padding: 36
Fields {}
}
ScrollView {
padding: 36
Selectors {}
}
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()
ScrollView {
padding: 36
Components {}
}
}
}

View file

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

View file

@ -10,13 +10,16 @@ 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 = volume;
sink.audio.volume = Math.min(volume, 1.0);
}
}
@ -42,6 +45,18 @@ 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,27 +1,19 @@
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

@ -0,0 +1,27 @@
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

@ -0,0 +1,43 @@
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: Theme.palette.base100
strokeColor: Theme.palette.base200
fillColor: Styling.theme.base100
strokeColor: Styling.theme.base200
strokeWidth: 8
PathAngleArc {

View file

@ -1,102 +0,0 @@
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
}
}
}
}