Merge branch 'end-4:main' into fix/workflow-run-on-forks

This commit is contained in:
Manpreet Singh
2025-11-17 19:00:43 +05:30
committed by GitHub
113 changed files with 2465 additions and 631 deletions
+17 -6
View File
@@ -2,22 +2,33 @@
- Please, please, please, make multiple PRs if you have many features/fixes, and don't shove your personal changes along with the PR, including changed defaults - Please, please, please, make multiple PRs if you have many features/fixes, and don't shove your personal changes along with the PR, including changed defaults
- We can accept features that we do not personally want, but in that case we will ask you to make it configurable/optionally loaded. - We can accept features that we do not personally want, but in that case we will ask you to make it configurable/optionally loaded.
- If you want to start working on something big to contribute, it might be a good idea to ask first to not waste your effort (but if you've already done it for yourself, it doesn't hurt to submit). - If you want to start working on something _big_ to contribute, it might be a good idea to ask first to not waste your effort (but if you've already done it for yourself, it doesn't hurt to submit).
# Code details # Translations
## Contributing to i18n See `dots/.config/quickshell/ii/translations/tools`
For contributing in translation (i18n) for Quickshell, see also `dots/.config/quickshell/ii/translations/tools`. # Code
## Dynamic loading ## Dynamic loading
- If something's not always necessary, especially when guarded by a config option to enable/disable, put it in a `Loader`. One tip with `Loader`s is sometimes you will need to declare positioning properties (like `anchors`) in the `Loader`, not the `sourceComponent`. - If something's not always necessary, especially when guarded by a config option to enable/disable, put it in a `Loader`
- Note that you will need to declare positioning properties (like `anchors`) in the `Loader`, not the `sourceComponent`
- When something that's to be dynamically loaded doesn't affect its parent layout, you can have a fading animation by using FadeLoader and set the `shown` prop instead of `active` and `visible`
## Practical concerns ## Practical concerns
- Make sure what you add does not require significant resources for a minor purpose or harm usability just for the sake of looking nice. The dotfiles must remain practical for daily driving. - Make sure what you add does not require significant resources for a minor purpose or harm usability just for the sake of looking nice. The dotfiles must remain practical for daily driving.
- If there is something really fancy and impractical anyway, add a config option for it and make sure it's disabled by default. - If there is something really fancy and impractical anyway, add a config option for it and make sure it's disabled by default (example: constantly rotating background clock)
## Style
- Spaces
- Space properties and children data into meaningful groups. (but of course, don't use 2+ blanks in a row)
- Put spaces between text and operators: `if (condition) { ... } else { ... }` instead of `if(condition){ ... }else{ ... }`
- As you can see, it's pretty easy to use lots of nesting. There's no hard limit, end-4 himself nests a lot too, but avoid/mitigate that:
- Prefer early return: Use something like `if (!condition) return; doStuff();` instead of `if (condition) { doStuff() }`
- If you feel it's a bother to refractor something into a new file, remember there's `component` to declare reusable components in the same file.
# Setting up # Setting up
+1 -1
View File
@@ -81,7 +81,7 @@ Widget system: Quickshell | Support: Yes
|:---|:---------------| |:---|:---------------|
| <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/ea0154a1-e984-4bb6-a424-23247cefe3c6" /> | <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/6eba0d57-2606-4cea-8993-e6f169e82e70" /> | | <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/ea0154a1-e984-4bb6-a424-23247cefe3c6" /> | <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/6eba0d57-2606-4cea-8993-e6f169e82e70" /> |
| Window management | Weeb power | | Window management | Weeb power |
| <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/e77a7c96-1905-4126-a2a0-434f818825a2" /> | <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/c8544e99-8881-477f-b83a-d6e35c0184a1" /> | | <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/a7e6d29c-e82c-4934-98db-36c810ec999b" /> | <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/c8544e99-8881-477f-b83a-d6e35c0184a1" /> |
### Other styles: Available at the end of the readme. ### Other styles: Available at the end of the readme.
+10 -3
View File
@@ -1,10 +1,17 @@
/diagnose.result /diagnose.result
/cache /cache
# Ignore Python cache files # Ignore Python cache files
__pycache__/ __pycache__/
*.py[cod] *.py[cod]
dots/.config/quickshell/ii/.qmlls.ini
.update-lock /dots/.config/quickshell/ii/.qmlls.ini
# exp-update
/.update-lock
# custom os-release
/os-release /os-release
#emacs backup
# Emacs auto backup file
*~ *~
+1
View File
@@ -70,6 +70,7 @@ x git submodule status --recursive
e "Checking distro" e "Checking distro"
x _check_distro_id x _check_distro_id
x cat os-release
#x _check_distro #x _check_distro
e "Checking variables" e "Checking variables"
+1 -1
View File
@@ -14,7 +14,7 @@ exec-once = sleep 1 && dbus-update-activation-environment --systemd WAYLAND_DISP
exec-once = hyprpm reload exec-once = hyprpm reload
# Audio # Audio
exec-once = easyeffects --gapplication-service exec-once = easyeffects --hide-window --service-mode
# Clipboard: history # Clipboard: history
# exec-once = wl-paste --watch cliphist store & # exec-once = wl-paste --watch cliphist store &
+2 -2
View File
@@ -24,8 +24,8 @@ bindit = ,Super_L, global, quickshell:workspaceNumber # [hidden]
bindit = ,Super_R, global, quickshell:workspaceNumber # [hidden] bindit = ,Super_R, global, quickshell:workspaceNumber # [hidden]
bindd = Super, V, Clipboard history >> clipboard, global, quickshell:overviewClipboardToggle # Clipboard history >> clipboard bindd = Super, V, Clipboard history >> clipboard, global, quickshell:overviewClipboardToggle # Clipboard history >> clipboard
bindd = Super, Period, Emoji >> clipboard, global, quickshell:overviewEmojiToggle # Emoji >> clipboard bindd = Super, Period, Emoji >> clipboard, global, quickshell:overviewEmojiToggle # Emoji >> clipboard
bindd = Super, Tab, Toggle overview, global, quickshell:overviewToggle # [hidden] Toggle overview/launcher (alt) bind = Super, Tab, global, quickshell:overviewWorkspacesToggle # [hidden] Toggle overview/launcher (alt)
bindd = Super, A, Toggle left sidebar, global, quickshell:sidebarLeftToggle # Toggle left sidebar bind = Super, A, global, quickshell:sidebarLeftToggle # Toggle left sidebar
bind = Super+Alt, A, global, quickshell:sidebarLeftToggleDetach # [hidden] bind = Super+Alt, A, global, quickshell:sidebarLeftToggleDetach # [hidden]
bind = Super, B, global, quickshell:sidebarLeftToggle # [hidden] bind = Super, B, global, quickshell:sidebarLeftToggle # [hidden]
bind = Super, O, global, quickshell:sidebarLeftToggle # [hidden] bind = Super, O, global, quickshell:sidebarLeftToggle # [hidden]
+2
View File
@@ -133,12 +133,14 @@ layerrule = blurpopups, quickshell:.*
layerrule = blur, quickshell:.* layerrule = blur, quickshell:.*
layerrule = ignorealpha 0.79, quickshell:.* layerrule = ignorealpha 0.79, quickshell:.*
layerrule = animation slide, quickshell:bar layerrule = animation slide, quickshell:bar
layerrule = noanim, quickshell:actionCenter
layerrule = animation slide bottom, quickshell:cheatsheet layerrule = animation slide bottom, quickshell:cheatsheet
layerrule = animation slide bottom, quickshell:dock layerrule = animation slide bottom, quickshell:dock
layerrule = animation popin 120%, quickshell:screenCorners layerrule = animation popin 120%, quickshell:screenCorners
layerrule = noanim, quickshell:lockWindowPusher layerrule = noanim, quickshell:lockWindowPusher
layerrule = animation fade, quickshell:notificationPopup layerrule = animation fade, quickshell:notificationPopup
layerrule = noanim, quickshell:overlay layerrule = noanim, quickshell:overlay
layerrule = ignorealpha 1, quickshell:overlay
layerrule = noanim, quickshell:overview layerrule = noanim, quickshell:overview
layerrule = animation slide bottom, quickshell:osk layerrule = animation slide bottom, quickshell:osk
layerrule = noanim, quickshell:polkit layerrule = noanim, quickshell:polkit
@@ -1,5 +1,5 @@
The "search" and "task view" icons are from here, with modifications The "start-here", "search" and "task view" icons are from here, with modifications
https://www.figma.com/community/file/1123040825921884189/windows-11 [Windows 11 by Joshua Oghenekaro Okwe - Figma](https://www.figma.com/community/file/1123040825921884189/windows-11)
License: CC BY 4.0 License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/deed.en)
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="24"
height="24"
fill="none"
viewBox="0 0 24 24"
version="1.1"
id="svg1"
sodipodi:docname="arrow-sync.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="25.868323"
inkscape:cx="14.245222"
inkscape:cy="12.447657"
inkscape:window-width="1498"
inkscape:window-height="1020"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<path
d="m 19.947024,13.17933 a 0.75,0.75 0 0 0 -0.907212,0.549312 7.251,7.251 0 0 1 -13.334866,1.873667 l 0.8908023,0.350894 a 0.75,0.75 0 0 0 0.6494514,-1.347747 l -0.100442,-0.04793 -2.6316174,-1.036623 a 0.75,0.75 0 0 0 -0.9241627,0.322228 l -0.047921,0.100457 -1.0366214,2.631619 a 0.75,0.75 0 0 0 1.3468323,0.649854 l 0.048321,-0.09951 0.3887326,-0.986859 A 8.75,8.75 0 0 0 20.494492,14.087329 0.75,0.75 0 0 0 19.946102,13.179722 Z M 21.068469,6.4543893 A 0.75,0.75 0 0 0 20.096388,6.8770607 L 19.707652,7.863919 A 8.75,8.75 0 0 0 3.5868012,9.5848274 0.75043107,0.75043107 0 1 0 5.0290446,10.000183 7.251,7.251 0 0 1 18.290631,8.3993655 l -0.8904,-0.3499798 a 0.75,0.75 0 1 0 -0.549014,1.3956769 l 2.631617,1.0366214 a 0.75,0.75 0 0 0 0.972088,-0.422667 L 21.491544,7.4273949 A 0.75,0.75 0 0 0 21.068874,6.455308 Z"
fill="#212121"
id="path1" />
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1 @@
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M4.293 8.293a1 1 0 0 1 1.414 0L12 14.586l6.293-6.293a1 1 0 1 1 1.414 1.414l-7 7a1 1 0 0 1-1.414 0l-7-7a1 1 0 0 1 0-1.414Z" fill="#212121"/></svg>

After

Width:  |  Height:  |  Size: 249 B

@@ -0,0 +1 @@
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M3.28 2.22a.75.75 0 0 0-1.06 1.06l5.905 5.905L4.81 10.33a1.25 1.25 0 0 0-.476 2.065L7.439 15.5 3 19.94V21h1.06l4.44-4.44 3.105 3.105a1.25 1.25 0 0 0 2.065-.476l1.145-3.313 5.905 5.904a.75.75 0 0 0 1.06-1.06L3.28 2.22Zm10.355 12.476-1.252 3.626-6.705-6.705 3.626-1.252 4.331 4.331Zm6.048-3.876-3.787 1.894 1.118 1.118 3.34-1.67a2.75 2.75 0 0 0 .714-4.404l-4.825-4.826a2.75 2.75 0 0 0-4.405.715l-1.67 3.34 1.118 1.117 1.894-3.787a1.25 1.25 0 0 1 2.002-.325l4.826 4.826a1.25 1.25 0 0 1-.325 2.002Z" fill="#212121"/></svg>

After

Width:  |  Height:  |  Size: 622 B

@@ -0,0 +1 @@
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m16.242 2.932 4.826 4.826a2.75 2.75 0 0 1-.715 4.404l-4.87 2.435a.75.75 0 0 0-.374.426l-1.44 4.166a1.25 1.25 0 0 1-2.065.476L8.5 16.561 4.06 21H3v-1.06l4.44-4.44-3.105-3.104a1.25 1.25 0 0 1 .476-2.066l4.166-1.44a.75.75 0 0 0 .426-.373l2.435-4.87a2.75 2.75 0 0 1 4.405-.715Zm3.766 5.886-4.826-4.826a1.25 1.25 0 0 0-2.002.325l-2.435 4.871a2.25 2.25 0 0 1-1.278 1.12l-3.789 1.31 6.705 6.704 1.308-3.789a2.25 2.25 0 0 1 1.12-1.277l4.872-2.436a1.25 1.25 0 0 0 .325-2.002Z" fill="#212121"/></svg>

After

Width:  |  Height:  |  Size: 594 B

@@ -0,0 +1 @@
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12.012 2.25c.734.008 1.465.093 2.182.253a.75.75 0 0 1 .582.649l.17 1.527a1.384 1.384 0 0 0 1.927 1.116l1.401-.615a.75.75 0 0 1 .85.174 9.792 9.792 0 0 1 2.204 3.792.75.75 0 0 1-.271.825l-1.242.916a1.381 1.381 0 0 0 0 2.226l1.243.915a.75.75 0 0 1 .272.826 9.797 9.797 0 0 1-2.204 3.792.75.75 0 0 1-.848.175l-1.407-.617a1.38 1.38 0 0 0-1.926 1.114l-.169 1.526a.75.75 0 0 1-.572.647 9.518 9.518 0 0 1-4.406 0 .75.75 0 0 1-.572-.647l-.168-1.524a1.382 1.382 0 0 0-1.926-1.11l-1.406.616a.75.75 0 0 1-.849-.175 9.798 9.798 0 0 1-2.204-3.796.75.75 0 0 1 .272-.826l1.243-.916a1.38 1.38 0 0 0 0-2.226l-1.243-.914a.75.75 0 0 1-.271-.826 9.793 9.793 0 0 1 2.204-3.792.75.75 0 0 1 .85-.174l1.4.615a1.387 1.387 0 0 0 1.93-1.118l.17-1.526a.75.75 0 0 1 .583-.65c.717-.159 1.45-.243 2.201-.252Zm0 1.5a9.135 9.135 0 0 0-1.354.117l-.109.977A2.886 2.886 0 0 1 6.525 7.17l-.898-.394a8.293 8.293 0 0 0-1.348 2.317l.798.587a2.881 2.881 0 0 1 0 4.643l-.799.588c.32.842.776 1.626 1.348 2.322l.905-.397a2.882 2.882 0 0 1 4.017 2.318l.11.984c.889.15 1.798.15 2.687 0l.11-.984a2.881 2.881 0 0 1 4.018-2.322l.905.396a8.296 8.296 0 0 0 1.347-2.318l-.798-.588a2.881 2.881 0 0 1 0-4.643l.796-.587a8.293 8.293 0 0 0-1.348-2.317l-.896.393a2.884 2.884 0 0 1-4.023-2.324l-.11-.976a8.988 8.988 0 0 0-1.333-.117ZM12 8.25a3.75 3.75 0 1 1 0 7.5 3.75 3.75 0 0 1 0-7.5Zm0 1.5a2.25 2.25 0 1 0 0 4.5 2.25 2.25 0 0 0 0-4.5Z" fill="#212121"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,24 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 6.2C4 4.98497 4.98497 4 6.2 4H28.2C29.415 4 30.4 4.98497 30.4 6.2V28.2C30.4 29.415 29.415 30.4 28.2 30.4H6.2C4.98497 30.4 4 29.415 4 28.2V6.2Z" fill="url(#paint0_radial_520_19)"/>
<path d="M32.6 6.2C32.6 4.98497 33.585 4 34.8 4H56.8C58.015 4 59 4.98497 59 6.2V28.2C59 29.415 58.015 30.4 56.8 30.4H34.8C33.585 30.4 32.6 29.415 32.6 28.2V6.2Z" fill="url(#paint1_radial_520_19)"/>
<path d="M32.6 34.8C32.6 33.585 33.585 32.6 34.8 32.6H56.8C58.015 32.6 59 33.585 59 34.8V56.8C59 58.015 58.015 59 56.8 59H34.8C33.585 59 32.6 58.015 32.6 56.8V34.8Z" fill="url(#paint2_radial_520_19)"/>
<path d="M4 34.8C4 33.585 4.98497 32.6 6.2 32.6H28.2C29.415 32.6 30.4 33.585 30.4 34.8V56.8C30.4 58.015 29.415 59 28.2 59H6.2C4.98497 59 4 58.015 4 56.8V34.8Z" fill="url(#paint3_radial_520_19)"/>
<defs>
<radialGradient id="paint0_radial_520_19" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(4 4) rotate(45) scale(77.7817)">
<stop stop-color="#0B9BFE"/>
<stop offset="1" stop-color="#0B9BFE"/>
</radialGradient>
<radialGradient id="paint1_radial_520_19" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(4 4) rotate(45) scale(77.7817)">
<stop stop-color="#0B9BFE"/>
<stop offset="1" stop-color="#0B9BFE"/>
</radialGradient>
<radialGradient id="paint2_radial_520_19" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(4 4) rotate(45) scale(77.7817)">
<stop stop-color="#0B9BFE"/>
<stop offset="1" stop-color="#0B9BFE"/>
</radialGradient>
<radialGradient id="paint3_radial_520_19" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(4 4) rotate(45) scale(77.7817)">
<stop stop-color="#0B9BFE"/>
<stop offset="1" stop-color="#0B9BFE"/>
</radialGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,24 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 6.2C4 4.98497 4.98497 4 6.2 4H28.2C29.415 4 30.4 4.98497 30.4 6.2V28.2C30.4 29.415 29.415 30.4 28.2 30.4H6.2C4.98497 30.4 4 29.415 4 28.2V6.2Z" fill="url(#paint0_radial_519_6)"/>
<path d="M32.6 6.2C32.6 4.98497 33.585 4 34.8 4H56.8C58.015 4 59 4.98497 59 6.2V28.2C59 29.415 58.015 30.4 56.8 30.4H34.8C33.585 30.4 32.6 29.415 32.6 28.2V6.2Z" fill="url(#paint1_radial_519_6)"/>
<path d="M32.6 34.8C32.6 33.585 33.585 32.6 34.8 32.6H56.8C58.015 32.6 59 33.585 59 34.8V56.8C59 58.015 58.015 59 56.8 59H34.8C33.585 59 32.6 58.015 32.6 56.8V34.8Z" fill="url(#paint2_radial_519_6)"/>
<path d="M4 34.8C4 33.585 4.98497 32.6 6.2 32.6H28.2C29.415 32.6 30.4 33.585 30.4 34.8V56.8C30.4 58.015 29.415 59 28.2 59H6.2C4.98497 59 4 58.015 4 56.8V34.8Z" fill="url(#paint3_radial_519_6)"/>
<defs>
<radialGradient id="paint0_radial_519_6" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(4 4) rotate(45) scale(77.7817)">
<stop stop-color="#81DFFF"/>
<stop offset="1" stop-color="#0A99F9"/>
</radialGradient>
<radialGradient id="paint1_radial_519_6" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(4 4) rotate(45) scale(77.7817)">
<stop stop-color="#81DFFF"/>
<stop offset="1" stop-color="#0A99F9"/>
</radialGradient>
<radialGradient id="paint2_radial_519_6" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(4 4) rotate(45) scale(77.7817)">
<stop stop-color="#81DFFF"/>
<stop offset="1" stop-color="#0A99F9"/>
</radialGradient>
<radialGradient id="paint3_radial_519_6" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(4 4) rotate(45) scale(77.7817)">
<stop stop-color="#81DFFF"/>
<stop offset="1" stop-color="#0A99F9"/>
</radialGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64"
height="64"
version="1.1"
viewBox="0 0 16.933 16.933"
id="svg2"
sodipodi:docname="system-search-checked-dark.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview2"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="4.65625"
inkscape:cx="32"
inkscape:cy="32"
inkscape:window-width="1197"
inkscape:window-height="1020"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g2" />
<defs
id="defs2">
<linearGradient
id="linearGradient1"
inkscape:collect="always">
<stop
style="stop-color:#565757;stop-opacity:1;"
offset="0"
id="stop3" />
<stop
style="stop-color:#4c4f52;stop-opacity:1;"
offset="1"
id="stop4" />
</linearGradient>
<linearGradient
id="linearGradient919"
x1="4.3106"
x2="14.36"
y1="8.4665"
y2="8.4665"
gradientTransform="matrix(1.226575,0,0,1.226575,-0.82407803,-6.4497629)"
gradientUnits="userSpaceOnUse">
<stop
stop-color="#3c8cff"
offset="0"
id="stop1"
style="stop-color:#5fe277;stop-opacity:1;" />
<stop
stop-color="#55b4ff"
offset="1"
id="stop2"
style="stop-color:#0078d3;stop-opacity:1;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1"
id="linearGradient4"
x1="-7.2925777"
y1="11.283"
x2="5.189723"
y2="11.283"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(11.677839,-7.3471437)" />
</defs>
<g
transform="translate(16.148 .19097)"
id="g2">
<rect
transform="rotate(45)"
x="2.891"
y="10.492"
width="7.4901"
height="1.583"
ry=".79147"
fill="#1955b9"
stroke-width="1.1651"
id="rect2"
style="stroke-width:1.16520206;stroke-dasharray:none;fill:#0175d1;fill-opacity:1" />
<circle
transform="rotate(120)"
cx="10.62641"
cy="3.9358561"
r="5.3520403"
fill="none"
stroke="url(#linearGradient919)"
stroke-linecap="round"
stroke-width="1.77822"
id="circle2"
style="fill:url(#linearGradient4);stroke:url(#linearGradient919);stroke-width:1.77822958;stroke-dasharray:none" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64"
height="64"
version="1.1"
viewBox="0 0 16.933 16.933"
id="svg2"
sodipodi:docname="system-search-checked-light.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview2"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="6.5849319"
inkscape:cx="26.95548"
inkscape:cy="26.423963"
inkscape:window-width="1257"
inkscape:window-height="1020"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<defs
id="defs2">
<linearGradient
id="linearGradient919"
x1="4.3106"
x2="14.36"
y1="8.4665"
y2="8.4665"
gradientTransform="matrix(1.226575,0,0,1.226575,-0.82407803,-6.4497629)"
gradientUnits="userSpaceOnUse">
<stop
stop-color="#3c8cff"
offset="0"
id="stop1"
style="stop-color:#5fe277;stop-opacity:1;" />
<stop
stop-color="#55b4ff"
offset="1"
id="stop2"
style="stop-color:#0078d3;stop-opacity:1;" />
</linearGradient>
</defs>
<rect
transform="rotate(45,7.8434785,19.587845)"
x="3.4592254"
y="10.492"
width="6.921874"
height="1.5830002"
ry="0.71336967"
fill="#1955b9"
stroke-width="1.1651"
id="rect2-5"
style="fill:#0077d4;fill-opacity:1;stroke-width:1.1652;stroke-dasharray:none" />
<circle
transform="rotate(120,8.0188717,4.757011)"
cx="10.62641"
cy="3.9358561"
r="5.3520403"
fill="none"
stroke="url(#linearGradient919)"
stroke-linecap="round"
stroke-width="1.77822"
id="circle2"
style="fill:none;stroke:url(#linearGradient919);stroke-width:1.77822958;stroke-dasharray:none" />
<g
transform="translate(16.148 .19097)"
id="g2" />
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -7,10 +7,11 @@
version="1.1" version="1.1"
viewBox="0 0 16.933 16.933" viewBox="0 0 16.933 16.933"
id="svg2" id="svg2"
sodipodi:docname="system-search.svg" sodipodi:docname="system-search-dark.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)" inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"> xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview <sodipodi:namedview
@@ -24,15 +25,27 @@
inkscape:deskcolor="#d1d1d1" inkscape:deskcolor="#d1d1d1"
inkscape:zoom="4.65625" inkscape:zoom="4.65625"
inkscape:cx="32" inkscape:cx="32"
inkscape:cy="32" inkscape:cy="31.892617"
inkscape:window-width="1061" inkscape:window-width="1061"
inkscape:window-height="1020" inkscape:window-height="835"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="0" inkscape:window-y="0"
inkscape:window-maximized="1" inkscape:window-maximized="1"
inkscape:current-layer="g2" /> inkscape:current-layer="g2" />
<defs <defs
id="defs2"> id="defs2">
<linearGradient
id="linearGradient1"
inkscape:collect="always">
<stop
style="stop-color:#565757;stop-opacity:1;"
offset="0"
id="stop3" />
<stop
style="stop-color:#4c4f52;stop-opacity:1;"
offset="1"
id="stop4" />
</linearGradient>
<linearGradient <linearGradient
id="linearGradient919" id="linearGradient919"
x1="4.3106" x1="4.3106"
@@ -52,6 +65,15 @@
id="stop2" id="stop2"
style="stop-color:#d7dcdf;stop-opacity:1;" /> style="stop-color:#d7dcdf;stop-opacity:1;" />
</linearGradient> </linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1"
id="linearGradient4"
x1="-7.2925777"
y1="11.283"
x2="5.189723"
y2="11.283"
gradientUnits="userSpaceOnUse" />
</defs> </defs>
<g <g
transform="translate(16.148 .19097)" transform="translate(16.148 .19097)"
@@ -77,6 +99,6 @@
stroke-linecap="round" stroke-linecap="round"
stroke-width="1.77822" stroke-width="1.77822"
id="circle2" id="circle2"
style="fill:#4f4f4f;fill-opacity:1;stroke:url(#linearGradient919)" /> style="fill:url(#linearGradient4);fill-opacity:1;stroke:url(#linearGradient919)" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="63.999989"
height="61.62962"
viewBox="0 0 26.999999 26"
fill="none"
version="1.1"
id="svg3"
sodipodi:docname="task-view-dark-pressed.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview3"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="6.0349946"
inkscape:cx="32.228695"
inkscape:cy="33.305746"
inkscape:window-width="1331"
inkscape:window-height="1020"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g3" />
<g
id="g3"
transform="translate(0.03879728,0.03736111)">
<g
id="g4"
transform="translate(-1.6875003,2.5312505)">
<rect
opacity="0.9"
x="9.4441719"
width="17.938911"
height="15.248073"
rx="0.89694548"
fill="#ffffff"
id="rect1"
y="0.8962484"
style="fill:url(#linearGradient4);fill-opacity:1;stroke:#e2e2e2;stroke-width:0.179719;stroke-dasharray:none;stroke-opacity:1"
transform="translate(-2.3652457,0.93944352)" />
<rect
y="3.8563478"
width="17.953642"
height="15.260596"
rx="0.89768213"
fill="url(#paint0_linear_505_17)"
id="rect2"
x="5.1897082"
style="mix-blend-mode:exclusion;fill:url(#paint0_linear_505_17-3);stroke-width:0.89775;stroke-dasharray:none" />
</g>
<g
id="g1"
transform="translate(-2.3652457,0.93944351)">
<g
style="mix-blend-mode:exclusion;stroke-width:1.00007574;stroke-dasharray:none"
id="g2"
transform="matrix(0.89768215,0,0,0.89768215,4.1799533,-0.09973431)" />
</g>
</g>
<defs
id="defs3">
<linearGradient
id="paint0_linear_505_17"
x1="-2.75374e-08"
y1="9.2399397"
x2="18.808399"
y2="26.838499"
gradientUnits="userSpaceOnUse">
<stop
stop-color="#717171"
id="stop2"
offset="0"
style="stop-color:#717171;stop-opacity:0.73333335;" />
<stop
offset="1"
stop-color="#4F4F4F"
id="stop3"
style="stop-color:#4f4f4f;stop-opacity:0.73333335;" />
</linearGradient>
<linearGradient
id="paint0_linear_505_17-3"
x1="-2.75374e-08"
y1="9.2399397"
x2="18.808399"
y2="26.838499"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.89768213,0,0,0.89768213,5.189708,-4.2227915)">
<stop
stop-color="#717171"
id="stop2-6"
offset="0"
style="stop-color:#717171;stop-opacity:0.60000002;" />
<stop
offset="1"
stop-color="#4F4F4F"
id="stop3-7"
style="stop-color:#565656;stop-opacity:0.60000002;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1"
id="linearGradient4"
x1="7.1907158"
y1="8.3216944"
x2="24.995911"
y2="10.507897"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(2.3203156,-0.89451377)" />
<linearGradient
id="linearGradient1"
inkscape:collect="always">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop1" />
<stop
style="stop-color:#e6e6e6;stop-opacity:1;"
offset="1"
id="stop4" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="63.999989"
height="61.62962"
viewBox="0 0 26.999999 26"
fill="none"
version="1.1"
id="svg3"
sodipodi:docname="task-view-checked-light.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview3"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="4.7640337"
inkscape:cx="21.200522"
inkscape:cy="37.573202"
inkscape:window-width="1238"
inkscape:window-height="612"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g3" />
<g
id="g3"
transform="translate(0.03879728,0.03736111)">
<g
id="g1"
transform="translate(-1.7324301,2.5761801)">
<g
style="mix-blend-mode:exclusion;stroke-width:0.999982;stroke-dasharray:none"
id="g2"
transform="matrix(0.89768215,0,0,0.89768215,5.2346381,-4.2677212)">
<rect
y="9"
width="20"
height="17"
rx="1"
fill="url(#paint0_linear_505_17)"
id="rect2"
x="0"
style="fill:url(#paint0_linear_505_17);stroke-width:0.999982;stroke-dasharray:none" />
</g>
<rect
opacity="0.9"
x="7.1238561"
width="17.938911"
height="15.248073"
rx="0.89694548"
fill="#ffffff"
id="rect1"
y="1.7907622"
style="fill:url(#linearGradient4);fill-opacity:1;stroke:#d4d4d4;stroke-width:0.179719;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
<defs
id="defs3">
<linearGradient
id="linearGradient1"
inkscape:collect="always">
<stop
style="stop-color:#ffffff;stop-opacity:0.80000001;"
offset="0"
id="stop1" />
<stop
style="stop-color:#e6e6e6;stop-opacity:0.80000001;"
offset="1"
id="stop4" />
</linearGradient>
<linearGradient
id="paint0_linear_505_17"
x1="-2.75374e-08"
y1="9.2399397"
x2="18.808399"
y2="26.838499"
gradientUnits="userSpaceOnUse">
<stop
stop-color="#717171"
id="stop2"
offset="0"
style="stop-color:#464543;stop-opacity:1;" />
<stop
offset="1"
stop-color="#4F4F4F"
id="stop3"
style="stop-color:#1f1f1f;stop-opacity:1;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1"
id="linearGradient4"
x1="7.1729918"
y1="8.4772339"
x2="25.013634"
y2="10.352362"
gradientUnits="userSpaceOnUse" />
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

@@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.modules.common.functions
Singleton { Singleton {
id: root id: root
@@ -147,6 +148,7 @@ Singleton {
property string networkEthernet: "kcmshell6 kcm_networkmanagement" property string networkEthernet: "kcmshell6 kcm_networkmanagement"
property string taskManager: "plasma-systemmonitor --page-name Processes" property string taskManager: "plasma-systemmonitor --page-name Processes"
property string terminal: "kitty -1" // This is only for shell actions property string terminal: "kitty -1" // This is only for shell actions
property string update: "kitty -1 --hold=yes fish -i -c 'sudo pacman -Syu'"
property string volumeMixer: `~/.config/hypr/hyprland/scripts/launch_first_available.sh "pavucontrol-qt" "pavucontrol"` property string volumeMixer: `~/.config/hypr/hyprland/scripts/launch_first_available.sh "pavucontrol-qt" "pavucontrol"`
} }
@@ -158,7 +160,8 @@ Singleton {
property string placementStrategy: "leastBusy" // "free", "leastBusy", "mostBusy" property string placementStrategy: "leastBusy" // "free", "leastBusy", "mostBusy"
property real x: 100 property real x: 100
property real y: 100 property real y: 100
property string style: "cookie" // Options: "cookie", "digital" property string style: "cookie" // Options: "cookie", "digital"
property string styleLocked: "cookie" // Options: "cookie", "digital"
property JsonObject cookie: JsonObject { property JsonObject cookie: JsonObject {
property bool aiStyling: false property bool aiStyling: false
property int sides: 14 property int sides: 14
@@ -236,13 +239,6 @@ Singleton {
property bool showPerformanceProfileToggle: false property bool showPerformanceProfileToggle: false
property bool showScreenRecord: false property bool showScreenRecord: false
} }
property JsonObject tray: JsonObject {
property bool monochromeIcons: true
property bool showItemId: false
property bool invertPinnedItems: true // Makes the below a whitelist for the tray and blacklist for the pinned area
property list<string> pinnedItems: [ ]
property bool filterPassive: true
}
property JsonObject workspaces: JsonObject { property JsonObject workspaces: JsonObject {
property bool monochromeIcons: true property bool monochromeIcons: true
property int shown: 10 property int shown: 10
@@ -264,6 +260,9 @@ Singleton {
property bool showUnreadCount: false property bool showUnreadCount: false
} }
} }
property JsonObject tooltips: JsonObject {
property bool clickToShow: false
}
} }
property JsonObject battery: JsonObject { property JsonObject battery: JsonObject {
@@ -426,6 +425,14 @@ Singleton {
property int historyLength: 60 property int historyLength: 60
} }
property JsonObject tray: JsonObject {
property bool monochromeIcons: true
property bool showItemId: false
property bool invertPinnedItems: true // Makes the below a whitelist for the tray and blacklist for the pinned area
property list<var> pinnedItems: [ "Fcitx" ]
property bool filterPassive: true
}
property JsonObject musicRecognition: JsonObject { property JsonObject musicRecognition: JsonObject {
property int timeout: 16 property int timeout: 16
property int interval: 4 property int interval: 4
@@ -532,6 +539,12 @@ Singleton {
} }
property bool secondPrecision: false property bool secondPrecision: false
} }
property JsonObject updates: JsonObject {
property int checkInterval: 120 // minutes
property int adviseUpdateThreshold: 75 // packages
property int stronglyAdviseUpdateThreshold: 200 // packages
}
property JsonObject wallpaperSelector: JsonObject { property JsonObject wallpaperSelector: JsonObject {
property bool useSystemFileDialog: false property bool useSystemFileDialog: false
@@ -559,6 +572,10 @@ Singleton {
} }
property JsonObject waffles: JsonObject { property JsonObject waffles: JsonObject {
// Animations on Windoes are kinda janky. Set the following to
// false will make (some) stuff also be like that for accuracy.
// Example: the right-click menu of the Start button
property bool smootherAnimations: true
property JsonObject bar: JsonObject { property JsonObject bar: JsonObject {
property bool bottom: true property bool bottom: true
property bool leftAlignApps: false property bool leftAlignApps: false
@@ -32,7 +32,9 @@ Singleton {
property string shellConfig: FileUtils.trimFileProtocol(`${Directories.config}/illogical-impulse`) property string shellConfig: FileUtils.trimFileProtocol(`${Directories.config}/illogical-impulse`)
property string shellConfigName: "config.json" property string shellConfigName: "config.json"
property string shellConfigPath: `${Directories.shellConfig}/${Directories.shellConfigName}` property string shellConfigPath: `${Directories.shellConfig}/${Directories.shellConfigName}`
property string todoPath: FileUtils.trimFileProtocol(`${Directories.state}/user/todo.json`) property string todoPath: FileUtils.trimFileProtocol(`${Directories.state}/user/todo.json`)
property string notesPath: FileUtils.trimFileProtocol(`${Directories.state}/user/notes.txt`)
property string conflictCachePath: FileUtils.trimFileProtocol(`${Directories.cache}/conflict-killer`)
property string notificationsPath: FileUtils.trimFileProtocol(`${Directories.cache}/notifications/notifications.json`) property string notificationsPath: FileUtils.trimFileProtocol(`${Directories.cache}/notifications/notifications.json`)
property string generatedMaterialThemePath: FileUtils.trimFileProtocol(`${Directories.state}/user/generated/colors.json`) property string generatedMaterialThemePath: FileUtils.trimFileProtocol(`${Directories.state}/user/generated/colors.json`)
property string generatedWallpaperCategoryPath: FileUtils.trimFileProtocol(`${Directories.state}/user/generated/wallpaper/category.txt`) property string generatedWallpaperCategoryPath: FileUtils.trimFileProtocol(`${Directories.state}/user/generated/wallpaper/category.txt`)
@@ -131,6 +131,14 @@ Singleton {
property real height: 600 property real height: 600
property int tabIndex: 0 property int tabIndex: 0
} }
property JsonObject notes: JsonObject {
property bool pinned: false
property bool clickthrough: true
property real x: 1400
property real y: 42
property real width: 460
property real height: 330
}
} }
property JsonObject timer: JsonObject { property JsonObject timer: JsonObject {
@@ -285,4 +285,14 @@ Singleton {
} }
return str; return str;
} }
function toTitleCase(str) {
// Replace "-" and "_" with space, then capitalize each word
return str.replace(/[-_]/g, " ").replace(
/\w\S*/g,
function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
}
);
}
} }
@@ -6,11 +6,13 @@ import qs.modules.common.widgets
Loader { Loader {
id: root id: root
property bool shown: true property bool shown: true
property alias fade: opacityBehavior.enabled
opacity: shown ? 1 : 0 opacity: shown ? 1 : 0
visible: opacity > 0 visible: opacity > 0
active: opacity > 0 active: opacity > 0
Behavior on opacity { Behavior on opacity {
id: opacityBehavior
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
} }
} }
@@ -18,10 +18,9 @@ StyledListView { // Scrollable window
required property int index required property int index
required property var modelData required property var modelData
popup: root.popup popup: root.popup
anchors.left: parent?.left width: ListView.view.width // https://doc.qt.io/qt-6/qml-qtquick-listview.html
anchors.right: parent?.right
notificationGroup: popup ? notificationGroup: popup ?
Notifications.popupGroupsByAppName[modelData] : Notifications.popupGroupsByAppName[modelData] :
Notifications.groupsByAppName[modelData] Notifications.groupsByAppName[modelData]
} }
} }
@@ -14,6 +14,10 @@ Item {
property real horizontalPadding: 10 property real horizontalPadding: 10
property real verticalPadding: 5 property real verticalPadding: 5
function updateAnchor() {
tooltipLoader.item?.anchor.updateAnchor();
}
readonly property bool internalVisibleCondition: (extraVisibleCondition && (parent.hovered === undefined || parent?.hovered)) || alternativeVisibleCondition readonly property bool internalVisibleCondition: (extraVisibleCondition && (parent.hovered === undefined || parent?.hovered)) || alternativeVisibleCondition
property var anchorEdges: Edges.Top property var anchorEdges: Edges.Top
property var anchorGravity: anchorEdges property var anchorGravity: anchorEdges
@@ -10,6 +10,7 @@ TextArea {
selectedTextColor: Appearance.m3colors.m3onSecondaryContainer selectedTextColor: Appearance.m3colors.m3onSecondaryContainer
selectionColor: Appearance.colors.colSecondaryContainer selectionColor: Appearance.colors.colSecondaryContainer
placeholderTextColor: Appearance.m3colors.m3outline placeholderTextColor: Appearance.m3colors.m3outline
color: Appearance.colors.colOnLayer0
font { font {
family: Appearance.font.family.main family: Appearance.font.family.main
pixelSize: Appearance?.font.pixelSize.small ?? 15 pixelSize: Appearance?.font.pixelSize.small ?? 15
@@ -5,7 +5,6 @@ import qs.services
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import Qt.labs.synchronizer
Item { Item {
id: root id: root
@@ -16,7 +16,7 @@ AbstractBackgroundWidget {
implicitHeight: contentColumn.implicitHeight implicitHeight: contentColumn.implicitHeight
implicitWidth: contentColumn.implicitWidth implicitWidth: contentColumn.implicitWidth
readonly property string clockStyle: Config.options.background.widgets.clock.style readonly property string clockStyle: GlobalStates.screenLocked ? Config.options.background.widgets.clock.styleLocked : Config.options.background.widgets.clock.style
readonly property bool forceCenter: (GlobalStates.screenLocked && Config.options.lock.centerClock) readonly property bool forceCenter: (GlobalStates.screenLocked && Config.options.lock.centerClock)
readonly property bool shouldShow: (!Config.options.background.widgets.clock.showOnlyWhenLocked || GlobalStates.screenLocked) readonly property bool shouldShow: (!Config.options.background.widgets.clock.showOnlyWhenLocked || GlobalStates.screenLocked)
property bool wallpaperSafetyTriggered: false property bool wallpaperSafetyTriggered: false
@@ -44,6 +44,7 @@ AbstractBackgroundWidget {
id: cookieClockLoader id: cookieClockLoader
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
shown: root.clockStyle === "cookie" && (root.shouldShow) shown: root.clockStyle === "cookie" && (root.shouldShow)
fade: false
sourceComponent: Column { sourceComponent: Column {
spacing: 10 spacing: 10
CookieClock { CookieClock {
@@ -61,6 +62,7 @@ AbstractBackgroundWidget {
id: digitalClockLoader id: digitalClockLoader
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
shown: root.clockStyle === "digital" && (root.shouldShow) shown: root.clockStyle === "digital" && (root.shouldShow)
fade: false
sourceComponent: ColumnLayout { sourceComponent: ColumnLayout {
id: clockColumn id: clockColumn
spacing: 6 spacing: 6
@@ -16,7 +16,7 @@ MouseArea {
implicitWidth: batteryProgress.implicitWidth implicitWidth: batteryProgress.implicitWidth
implicitHeight: Appearance.sizes.barHeight implicitHeight: Appearance.sizes.barHeight
hoverEnabled: true hoverEnabled: !Config.options.bar.tooltips.clickToShow
ClippedProgressBar { ClippedProgressBar {
id: batteryProgress id: batteryProgress
@@ -40,8 +40,7 @@ Item {
MouseArea { MouseArea {
id: mouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: !Config.options.bar.tooltips.clickToShow
acceptedButtons: Qt.NoButton
ClockWidgetPopup { ClockWidgetPopup {
hoverTarget: mouseArea hoverTarget: mouseArea
@@ -9,7 +9,7 @@ MouseArea {
property bool alwaysShowAllResources: false property bool alwaysShowAllResources: false
implicitWidth: rowLayout.implicitWidth + rowLayout.anchors.leftMargin + rowLayout.anchors.rightMargin implicitWidth: rowLayout.implicitWidth + rowLayout.anchors.leftMargin + rowLayout.anchors.rightMargin
implicitHeight: Appearance.sizes.barHeight implicitHeight: Appearance.sizes.barHeight
hoverEnabled: true hoverEnabled: !Config.options.bar.tooltips.clickToShow
RowLayout { RowLayout {
id: rowLayout id: rowLayout
@@ -1,10 +1,11 @@
import qs.modules.common
import qs.modules.common.widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import Quickshell.Services.SystemTray import Quickshell.Services.SystemTray
import qs.services
import qs.modules.common
import qs.modules.common.widgets
Item { Item {
id: root id: root
@@ -17,13 +18,8 @@ Item {
property bool showOverflowMenu: true property bool showOverflowMenu: true
property var activeMenu: null property var activeMenu: null
property bool smartTray: Config.options.bar.tray.filterPassive property list<var> pinnedItems: TrayService.pinnedItems
property list<var> itemsInUserList: SystemTray.items.values.filter(i => (Config.options.bar.tray.pinnedItems.includes(i.id) && (!smartTray || i.status !== Status.Passive))) property list<var> unpinnedItems: TrayService.unpinnedItems
property list<var> itemsNotInUserList: SystemTray.items.values.filter(i => (!Config.options.bar.tray.pinnedItems.includes(i.id) && (!smartTray || i.status !== Status.Passive)))
property bool invertPins: Config.options.bar.tray.invertPinnedItems
property list<var> pinnedItems: invertPins ? itemsNotInUserList : itemsInUserList
property list<var> unpinnedItems: invertPins ? itemsInUserList : itemsNotInUserList
onUnpinnedItemsChanged: { onUnpinnedItemsChanged: {
if (unpinnedItems.length == 0) root.closeOverflowMenu(); if (unpinnedItems.length == 0) root.closeOverflowMenu();
} }
@@ -1,11 +1,12 @@
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Services.SystemTray import Quickshell.Services.SystemTray
import Quickshell.Widgets import Quickshell.Widgets
import Qt5Compat.GraphicalEffects import Qt5Compat.GraphicalEffects
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
MouseArea { MouseArea {
id: root id: root
@@ -31,10 +32,7 @@ MouseArea {
event.accepted = true; event.accepted = true;
} }
onEntered: { onEntered: {
tooltip.text = item.tooltipTitle.length > 0 ? item.tooltipTitle tooltip.text = TrayService.getTooltipForItem(root.item);
: (item.title.length > 0 ? item.title : item.id);
if (item.tooltipDescription.length > 0) tooltip.text += " • " + item.tooltipDescription;
if (Config.options.bar.tray.showItemId) tooltip.text += "\n[" + item.id + "]";
} }
Loader { Loader {
@@ -65,7 +63,7 @@ MouseArea {
IconImage { IconImage {
id: trayIcon id: trayIcon
visible: !Config.options.bar.tray.monochromeIcons visible: !Config.options.tray.monochromeIcons
source: root.item.icon source: root.item.icon
anchors.centerIn: parent anchors.centerIn: parent
width: parent.width width: parent.width
@@ -73,7 +71,7 @@ MouseArea {
} }
Loader { Loader {
active: Config.options.bar.tray.monochromeIcons active: Config.options.tray.monochromeIcons
anchors.fill: trayIcon anchors.fill: trayIcon
sourceComponent: Item { sourceComponent: Item {
Desaturate { Desaturate {
@@ -13,15 +13,19 @@ MouseArea {
implicitWidth: rowLayout.implicitWidth + 10 * 2 implicitWidth: rowLayout.implicitWidth + 10 * 2
implicitHeight: Appearance.sizes.barHeight implicitHeight: Appearance.sizes.barHeight
hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: !Config.options.bar.tooltips.clickToShow
onPressed: { onPressed: {
Weather.getData(); if (mouse.button === Qt.RightButton) {
Quickshell.execDetached(["notify-send", Weather.getData();
Translation.tr("Weather"), Quickshell.execDetached(["notify-send",
Translation.tr("Refreshing (manually triggered)") Translation.tr("Weather"),
, "-a", "Shell" Translation.tr("Refreshing (manually triggered)")
]) , "-a", "Shell"
])
mouse.accepted = false
}
} }
RowLayout { RowLayout {
@@ -5,7 +5,6 @@ import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import Qt5Compat.GraphicalEffects import Qt5Compat.GraphicalEffects
import Qt.labs.synchronizer
import Quickshell.Io import Quickshell.Io
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
@@ -67,11 +67,7 @@ DockButton {
} }
altAction: () => { altAction: () => {
if (Config.options.dock.pinnedApps.indexOf(appToplevel.appId) !== -1) { TaskbarApps.togglePin(appToplevel.appId);
Config.options.dock.pinnedApps = Config.options.dock.pinnedApps.filter(id => id !== appToplevel.appId)
} else {
Config.options.dock.pinnedApps = Config.options.dock.pinnedApps.concat([appToplevel.appId])
}
} }
contentItem: Loader { contentItem: Loader {
@@ -25,7 +25,8 @@ Scope {
exclusionMode: ExclusionMode.Ignore exclusionMode: ExclusionMode.Ignore
WlrLayershell.namespace: "quickshell:overlay" WlrLayershell.namespace: "quickshell:overlay"
WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.keyboardFocus: GlobalStates.overlayOpen ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None // Use OnDemand for pinned widgets to allow focus switching with mouse clicks
WlrLayershell.keyboardFocus: GlobalStates.overlayOpen ? WlrKeyboardFocus.Exclusive : (OverlayContext.clickableWidgets.length > 0 ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None)
visible: true visible: true
color: "transparent" color: "transparent"
@@ -11,6 +11,7 @@ Singleton {
{ identifier: "floatingImage", materialSymbol: "imagesmode" }, { identifier: "floatingImage", materialSymbol: "imagesmode" },
{ identifier: "recorder", materialSymbol: "screen_record" }, { identifier: "recorder", materialSymbol: "screen_record" },
{ identifier: "resources", materialSymbol: "browse_activity" }, { identifier: "resources", materialSymbol: "browse_activity" },
{ identifier: "notes", materialSymbol: "note_stack" },
{ identifier: "volumeMixer", materialSymbol: "volume_up" }, { identifier: "volumeMixer", materialSymbol: "volume_up" },
] ]
@@ -8,10 +8,11 @@ import Quickshell
import Quickshell.Bluetooth import Quickshell.Bluetooth
import qs.modules.ii.overlay.crosshair import qs.modules.ii.overlay.crosshair
import qs.modules.ii.overlay.volumeMixer import qs.modules.ii.overlay.volumeMixer
import qs.modules.ii.overlay.floatingImage
import qs.modules.ii.overlay.fpsLimiter import qs.modules.ii.overlay.fpsLimiter
import qs.modules.ii.overlay.recorder import qs.modules.ii.overlay.recorder
import qs.modules.ii.overlay.resources import qs.modules.ii.overlay.resources
import qs.modules.ii.overlay.floatingImage import qs.modules.ii.overlay.notes
DelegateChooser { DelegateChooser {
id: root id: root
@@ -22,5 +23,6 @@ DelegateChooser {
DelegateChoice { roleValue: "fpsLimiter"; FpsLimiter {} } DelegateChoice { roleValue: "fpsLimiter"; FpsLimiter {} }
DelegateChoice { roleValue: "recorder"; Recorder {} } DelegateChoice { roleValue: "recorder"; Recorder {} }
DelegateChoice { roleValue: "resources"; Resources {} } DelegateChoice { roleValue: "resources"; Resources {} }
DelegateChoice { roleValue: "notes"; Notes {} }
DelegateChoice { roleValue: "volumeMixer"; VolumeMixer {} } DelegateChoice { roleValue: "volumeMixer"; VolumeMixer {} }
} }
@@ -0,0 +1,17 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.services
import qs.modules.common
import qs.modules.ii.overlay
StyledOverlayWidget {
id: root
title: Translation.tr("Notes")
showCenterButton: true
contentItem: NotesContent {
radius: root.contentRadius
isClickthrough: root.clickthrough
}
}
@@ -0,0 +1,292 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.ii.overlay
OverlayBackground {
id: root
property alias content: textInput.text
property bool pendingReload: false
property var copyListEntries: []
property string lastParsedCopylistText: ""
property var parsedCopylistLines: []
property bool isClickthrough: false
property real maxCopyButtonSize: 20
Component.onCompleted: {
noteFile.reload();
updateCopyListEntries();
}
function saveContent() {
if (!textInput)
return;
noteFile.setText(root.content);
}
function focusAtEnd() {
if (!textInput)
return;
textInput.forceActiveFocus();
const endPos = root.content.length;
applySelection(endPos, endPos);
}
function applySelection(cursorPos, anchorPos) {
if (!textInput)
return;
const textLength = root.content.length;
const cursor = Math.max(0, Math.min(cursorPos, textLength));
const anchor = Math.max(0, Math.min(anchorPos, textLength));
textInput.select(anchor, cursor);
if (cursor === anchor)
textInput.deselect();
}
function scheduleCopylistUpdate(immediate = false) {
if (!textInput)
return;
if (immediate) {
copyListDebounce?.stop();
updateCopyListEntries();
} else {
copyListDebounce.restart();
}
}
function updateCopyListEntries() {
if (!textInput)
return;
const textValue = root.content;
if (!textValue || textValue.length === 0) {
lastParsedCopylistText = "";
parsedCopylistLines = [];
root.copyListEntries = [];
return;
}
if (textValue !== lastParsedCopylistText) {
const lineRegex = /(.*?)(\r?\n|$)/g;
let match = null;
const parsed = [];
while ((match = lineRegex.exec(textValue)) !== null) {
const lineText = match[1];
const newlineText = match[2];
const lineStart = match.index;
const lineEnd = lineStart + lineText.length;
const bulletMatch = lineText.match(/^\s*-\s+(.*\S)\s*$/);
if (bulletMatch) {
parsed.push({
content: bulletMatch[1].trim(),
start: lineStart,
end: lineEnd
});
}
if (newlineText === "")
break;
}
lastParsedCopylistText = textValue;
parsedCopylistLines = parsed;
if (parsed.length === 0) {
root.copyListEntries = [];
return;
}
}
updateCopylistPositions();
}
function updateCopylistPositions() {
if (!textInput || parsedCopylistLines.length === 0)
return;
const rawSelectionStart = textInput.selectionStart;
const rawSelectionEnd = textInput.selectionEnd;
const selectionStart = rawSelectionStart === -1 ? textInput.cursorPosition : rawSelectionStart;
const selectionEnd = rawSelectionEnd === -1 ? textInput.cursorPosition : rawSelectionEnd;
const rangeStart = Math.min(selectionStart, selectionEnd);
const rangeEnd = Math.max(selectionStart, selectionEnd);
const entries = parsedCopylistLines.map(line => {
// Don't show copy button if line is (partially) selected
const caretIntersects = rangeEnd > line.start && rangeStart <= line.end;
if (caretIntersects)
return null;
const startRect = textInput.positionToRectangle(line.start);
let endRect = textInput.positionToRectangle(line.end);
if (!isFinite(startRect.y))
return null;
if (!isFinite(endRect.y))
endRect = startRect;
const lineBottom = endRect.y + endRect.height;
const rectHeight = Math.max(lineBottom - startRect.y, textInput.font.pixelSize + 8);
return {
content: line.content,
y: startRect.y,
height: rectHeight
};
}).filter(entry => entry !== null);
root.copyListEntries = entries;
}
implicitWidth: 300
implicitHeight: 200
ColumnLayout {
id: contentItem
anchors.fill: parent
spacing: -16
ScrollView {
id: editorScrollView
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
ScrollBar.vertical.policy: ScrollBar.AsNeeded
onWidthChanged: root.scheduleCopylistUpdate(true)
StyledTextArea { // This has to be a direct child of ScrollView for proper scrolling
id: textInput
anchors {
left: parent.left
right: parent.right
}
wrapMode: TextEdit.Wrap
placeholderText: Translation.tr("Write something here...\nUse '-' to create copyable bullet points, like this:\n\nSheep fricker\n- 4x Slab\n- 1x Boat\n- 4x Redstone Dust\n- 1x Sticky Piston\n- 1x End Rod\n- 4x Redstone Repeater\n- 1x Redstone Torch\n- 1x Sheep")
selectByMouse: true
persistentSelection: true
textFormat: TextEdit.PlainText
background: null
padding: 24
onTextChanged: {
if (textInput.activeFocus) {
saveDebounce.restart();
}
root.scheduleCopylistUpdate(true);
}
onHeightChanged: root.scheduleCopylistUpdate(true)
onContentHeightChanged: root.scheduleCopylistUpdate(true)
onCursorPositionChanged: root.scheduleCopylistUpdate()
onSelectionStartChanged: root.scheduleCopylistUpdate()
onSelectionEndChanged: root.scheduleCopylistUpdate()
}
Item {
anchors.fill: parent
visible: root.copyListEntries.length > 0
clip: true
Repeater {
model: ScriptModel {
values: root.copyListEntries
}
delegate: RippleButton {
id: copyButton
required property var modelData
readonly property real lineHeight: Math.min(Math.max(modelData.height, Appearance.font.pixelSize.normal + 6), root.maxCopyButtonSize)
readonly property real iconSizeLocal: Appearance.font.pixelSize.normal
readonly property real hitPadding: 6
property bool justCopied: false
implicitHeight: lineHeight
implicitWidth: lineHeight
buttonRadius: height / 2
y: modelData.y
anchors.right: parent.right
anchors.rightMargin: 10
z: 5
Timer {
id: resetState
interval: 700
onTriggered: {
copyButton.justCopied = false;
}
}
onClicked: {
Quickshell.clipboardText = copyButton.modelData.content;
justCopied = true;
resetState.start();
}
contentItem: Item {
anchors.centerIn: parent
MaterialSymbol {
id: iconItem
anchors.centerIn: parent
text: copyButton.justCopied ? "check" : "content_copy"
iconSize: copyButton.iconSizeLocal
color: Appearance.colors.colOnLayer1
}
}
}
}
}
}
StyledText {
id: statusLabel
Layout.fillWidth: true
Layout.margins: 16
horizontalAlignment: Text.AlignRight
text: saveDebounce.running ? Translation.tr("Saving...") : Translation.tr("Saved ")
color: Appearance.colors.colSubtext
}
}
Timer {
id: saveDebounce
interval: 500
repeat: false
onTriggered: saveContent()
}
Timer {
id: copyListDebounce
interval: 100
repeat: false
onTriggered: updateCopylistPositions()
}
FileView {
id: noteFile
path: Qt.resolvedUrl(Directories.notesPath)
onLoaded: {
root.content = noteFile.text();
if (root.content !== root.content) {
const previousCursor = textInput.cursorPosition;
const previousAnchor = textInput.selectionStart;
root.content = root.content;
applySelection(previousCursor, previousAnchor);
}
if (pendingReload) {
pendingReload = false;
Qt.callLater(root.focusAtEnd);
}
Qt.callLater(root.updateCopyListEntries);
}
onLoadFailed: error => {
if (error === FileViewError.FileNotFound) {
root.content = "";
noteFile.setText(root.content);
if (pendingReload) {
pendingReload = false;
Qt.callLater(root.focusAtEnd);
}
Qt.callLater(root.updateCopyListEntries);
} else {
console.log("[Overlay Notes] Error loading file: " + error);
}
}
}
}
@@ -5,7 +5,6 @@ import QtQuick.Layouts
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import Qt5Compat.GraphicalEffects import Qt5Compat.GraphicalEffects
import Qt.labs.synchronizer
import qs import qs
import qs.services import qs.services
import qs.modules.common import qs.modules.common
@@ -167,6 +167,9 @@ Scope {
function toggle() { function toggle() {
GlobalStates.overviewOpen = !GlobalStates.overviewOpen; GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
} }
function workspacesToggle() {
GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
}
function close() { function close() {
GlobalStates.overviewOpen = false; GlobalStates.overviewOpen = false;
} }
@@ -189,6 +192,14 @@ Scope {
GlobalStates.overviewOpen = !GlobalStates.overviewOpen; GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
} }
} }
GlobalShortcut {
name: "overviewWorkspacesToggle"
description: "Toggles overview on press"
onPressed: {
GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
}
}
GlobalShortcut { GlobalShortcut {
name: "overviewClose" name: "overviewClose"
description: "Closes overview" description: "Closes overview"
@@ -285,48 +285,36 @@ Rectangle {
} }
} }
} }
Repeater { Repeater {
model: ScriptModel { model: ScriptModel {
values: Array.from({ length: root.messageBlocks.length }, (msg, i) => { values: root.messageBlocks
return ({
type: root.messageBlocks[i].type
})
});
} }
delegate: DelegateChooser { delegate: DelegateChooser {
id: messageDelegate id: messageDelegate
role: "type" role: "type"
DelegateChoice { roleValue: "code"; MessageCodeBlock { DelegateChoice { roleValue: "code"; MessageCodeBlock {
required property int index
property var thisBlock: root.messageBlocks[index]
editing: root.editing editing: root.editing
renderMarkdown: root.renderMarkdown renderMarkdown: root.renderMarkdown
enableMouseSelection: root.enableMouseSelection enableMouseSelection: root.enableMouseSelection
segmentContent: thisBlock.content segmentContent: modelData.content
segmentLang: thisBlock.lang segmentLang: modelData.lang
messageData: root.messageData messageData: root.messageData
} } } }
DelegateChoice { roleValue: "think"; MessageThinkBlock { DelegateChoice { roleValue: "think"; MessageThinkBlock {
required property int index
property var thisBlock: root.messageBlocks[index]
editing: root.editing editing: root.editing
renderMarkdown: root.renderMarkdown renderMarkdown: root.renderMarkdown
enableMouseSelection: root.enableMouseSelection enableMouseSelection: root.enableMouseSelection
segmentContent: thisBlock.content segmentContent: modelData.content
messageData: root.messageData messageData: root.messageData
done: root.messageData?.done ?? false done: root.messageData?.done ?? false
completed: thisBlock.completed ?? false completed: modelData.completed ?? false
} } } }
DelegateChoice { roleValue: "text"; MessageTextBlock { DelegateChoice { roleValue: "text"; MessageTextBlock {
required property int index
property var thisBlock: root.messageBlocks[index]
editing: root.editing editing: root.editing
renderMarkdown: root.renderMarkdown renderMarkdown: root.renderMarkdown
enableMouseSelection: root.enableMouseSelection enableMouseSelection: root.enableMouseSelection
segmentContent: thisBlock.content segmentContent: modelData.content
messageData: root.messageData messageData: root.messageData
done: root.messageData?.done ?? false done: root.messageData?.done ?? false
forceDisableChunkSplitting: root.messageData?.content.includes("```") ?? true forceDisableChunkSplitting: root.messageData?.content.includes("```") ?? true
@@ -156,7 +156,6 @@ Item {
property bool editing: root.editing property bool editing: root.editing
property bool renderMarkdown: root.renderMarkdown property bool renderMarkdown: root.renderMarkdown
property bool enableMouseSelection: root.enableMouseSelection property bool enableMouseSelection: root.enableMouseSelection
property string segmentContent: root.segmentContent
property var messageData: root.messageData property var messageData: root.messageData
property bool done: root.done property bool done: root.done
@@ -165,8 +164,9 @@ Item {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
segmentContent: root.segmentContent
} }
} }
} }
} }
} }
@@ -12,6 +12,7 @@ AndroidQuickToggleButton {
name: Translation.tr("Bluetooth") name: Translation.tr("Bluetooth")
statusText: BluetoothStatus.firstActiveDevice?.name ?? Translation.tr("No device") statusText: BluetoothStatus.firstActiveDevice?.name ?? Translation.tr("No device")
available: BluetoothStatus.available
toggled: BluetoothStatus.enabled toggled: BluetoothStatus.enabled
buttonIcon: BluetoothStatus.connected ? "bluetooth_connected" : BluetoothStatus.enabled ? "bluetooth" : "bluetooth_disabled" buttonIcon: BluetoothStatus.connected ? "bluetooth_connected" : BluetoothStatus.enabled ? "bluetooth" : "bluetooth_disabled"
mainAction: () => { mainAction: () => {
@@ -27,4 +28,3 @@ AndroidQuickToggleButton {
) )
} }
} }
@@ -9,6 +9,7 @@ AndroidQuickToggleButton {
name: Translation.tr("EasyEffects") name: Translation.tr("EasyEffects")
available: EasyEffects.available
toggled: EasyEffects.active toggled: EasyEffects.active
buttonIcon: "graphic_eq" buttonIcon: "graphic_eq"
@@ -15,6 +15,7 @@ GroupButton {
required property string name required property string name
required property var mainAction required property var mainAction
property string statusText: toggled ? Translation.tr("Active") : Translation.tr("Inactive") property string statusText: toggled ? Translation.tr("Active") : Translation.tr("Inactive")
property bool available: true
required property real baseCellWidth required property real baseCellWidth
required property real baseCellHeight required property real baseCellHeight
@@ -42,6 +43,7 @@ GroupButton {
signal openMenu() signal openMenu()
enabled: available || editMode
padding: 6 padding: 6
horizontalPadding: padding horizontalPadding: padding
verticalPadding: padding verticalPadding: padding
@@ -52,8 +54,8 @@ GroupButton {
colBackgroundToggledActive: (altAction && expandedSize) ? Appearance.colors.colLayer2Active : Appearance.colors.colPrimaryActive colBackgroundToggledActive: (altAction && expandedSize) ? Appearance.colors.colLayer2Active : Appearance.colors.colPrimaryActive
buttonRadius: toggled ? Appearance.rounding.large : height / 2 buttonRadius: toggled ? Appearance.rounding.large : height / 2
buttonRadiusPressed: Appearance.rounding.normal buttonRadiusPressed: Appearance.rounding.normal
property color colText: (toggled && !(altAction && expandedSize)) ? Appearance.colors.colOnPrimary : Appearance.colors.colOnLayer2 property color colText: (toggled && !(altAction && expandedSize) && enabled) ? Appearance.colors.colOnPrimary : ColorUtils.transparentize(Appearance.colors.colOnLayer2, enabled ? 0 : 0.7)
property color colIcon: expandedSize ? (root.toggled ? Appearance.colors.colOnPrimary : Appearance.colors.colOnLayer3) : colText property color colIcon: expandedSize ? ((root.toggled) ? Appearance.colors.colOnPrimary : Appearance.colors.colOnLayer3) : colText
onClicked: { onClicked: {
if (root.expandedSize && root.altAction) root.altAction(); if (root.expandedSize && root.altAction) root.altAction();
@@ -15,7 +15,7 @@ MouseArea {
readonly property bool isLow: percentage <= Config.options.battery.low / 100 readonly property bool isLow: percentage <= Config.options.battery.low / 100
implicitHeight: batteryProgress.implicitHeight implicitHeight: batteryProgress.implicitHeight
hoverEnabled: true hoverEnabled: !Config.options.bar.tooltips.clickToShow
ClippedProgressBar { ClippedProgressBar {
id: batteryProgress id: batteryProgress
@@ -9,7 +9,7 @@ MouseArea {
property bool alwaysShowAllResources: false property bool alwaysShowAllResources: false
implicitHeight: columnLayout.implicitHeight implicitHeight: columnLayout.implicitHeight
implicitWidth: columnLayout.implicitWidth implicitWidth: columnLayout.implicitWidth
hoverEnabled: true hoverEnabled: !Config.options.bar.tooltips.clickToShow
ColumnLayout { ColumnLayout {
id: columnLayout id: columnLayout
@@ -33,8 +33,7 @@ Item {
MouseArea { MouseArea {
id: mouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: !Config.options.bar.tooltips.clickToShow
acceptedButtons: Qt.NoButton
Bar.ClockWidgetPopup { Bar.ClockWidgetPopup {
hoverTarget: mouseArea hoverTarget: mouseArea
@@ -28,7 +28,7 @@ MouseArea {
} }
acceptedButtons: Qt.MiddleButton | Qt.BackButton | Qt.ForwardButton | Qt.RightButton | Qt.LeftButton acceptedButtons: Qt.MiddleButton | Qt.BackButton | Qt.ForwardButton | Qt.RightButton | Qt.LeftButton
hoverEnabled: true hoverEnabled: !Config.options.bar.tooltips.clickToShow
onPressed: (event) => { onPressed: (event) => {
if (event.button === Qt.MiddleButton) { if (event.button === Qt.MiddleButton) {
activePlayer.togglePlaying(); activePlayer.togglePlaying();
@@ -55,6 +55,20 @@ ContentPage {
ContentSection { ContentSection {
icon: "clock_loader_40" icon: "clock_loader_40"
title: Translation.tr("Widget: Clock") title: Translation.tr("Widget: Clock")
id: settingsClock
function stylePresent(styleName) {
if (!Config.options.background.widgets.clock.showOnlyWhenLocked && Config.options.background.widgets.clock.style === styleName) {
return true;
}
if (Config.options.background.widgets.clock.styleLocked === styleName) {
return true;
}
return false;
}
readonly property bool digitalPresent: stylePresent("digital")
readonly property bool cookiePresent: stylePresent("cookie")
ConfigRow { ConfigRow {
Layout.fillWidth: true Layout.fillWidth: true
@@ -107,6 +121,7 @@ ContentPage {
} }
ContentSubsection { ContentSubsection {
visible: !Config.options.background.widgets.clock.showOnlyWhenLocked
title: Translation.tr("Clock style") title: Translation.tr("Clock style")
ConfigSelectionArray { ConfigSelectionArray {
currentValue: Config.options.background.widgets.clock.style currentValue: Config.options.background.widgets.clock.style
@@ -129,7 +144,29 @@ ContentPage {
} }
ContentSubsection { ContentSubsection {
visible: Config.options.background.widgets.clock.style === "digital" title: Translation.tr("Clock style (locked)")
ConfigSelectionArray {
currentValue: Config.options.background.widgets.clock.styleLocked
onSelected: newValue => {
Config.options.background.widgets.clock.styleLocked = newValue;
}
options: [
{
displayName: Translation.tr("Digital"),
icon: "timer_10",
value: "digital"
},
{
displayName: Translation.tr("Cookie"),
icon: "cookie",
value: "cookie"
}
]
}
}
ContentSubsection {
visible: settingsClock.digitalPresent
title: Translation.tr("Digital clock settings") title: Translation.tr("Digital clock settings")
ConfigSwitch { ConfigSwitch {
@@ -143,7 +180,7 @@ ContentPage {
} }
ContentSubsection { ContentSubsection {
visible: Config.options.background.widgets.clock.style === "cookie" visible: settingsClock.cookiePresent
title: Translation.tr("Cookie clock settings") title: Translation.tr("Cookie clock settings")
ConfigSwitch { ConfigSwitch {
@@ -197,7 +234,7 @@ ContentPage {
ConfigRow { ConfigRow {
ConfigSwitch { ConfigSwitch {
enabled: Config.options.background.widgets.clock.style === "cookie" && Config.options.background.widgets.clock.cookie.dialNumberStyle === "dots" || Config.options.background.widgets.clock.cookie.dialNumberStyle === "full" enabled: Config.options.background.widgets.clock.cookie.dialNumberStyle === "dots" || Config.options.background.widgets.clock.cookie.dialNumberStyle === "full"
buttonIcon: "brightness_7" buttonIcon: "brightness_7"
text: Translation.tr("Hour marks") text: Translation.tr("Hour marks")
checked: Config.options.background.widgets.clock.cookie.hourMarks checked: Config.options.background.widgets.clock.cookie.hourMarks
@@ -213,7 +250,7 @@ ContentPage {
} }
ConfigSwitch { ConfigSwitch {
enabled: Config.options.background.widgets.clock.style === "cookie" && Config.options.background.widgets.clock.cookie.dialNumberStyle !== "numbers" enabled: Config.options.background.widgets.clock.cookie.dialNumberStyle !== "numbers"
buttonIcon: "timer_10" buttonIcon: "timer_10"
text: Translation.tr("Digits in the middle") text: Translation.tr("Digits in the middle")
checked: Config.options.background.widgets.clock.cookie.timeIndicators checked: Config.options.background.widgets.clock.cookie.timeIndicators
@@ -231,7 +268,7 @@ ContentPage {
} }
ContentSubsection { ContentSubsection {
visible: Config.options.background.widgets.clock.style === "cookie" visible: settingsClock.cookiePresent
title: Translation.tr("Dial style") title: Translation.tr("Dial style")
ConfigSelectionArray { ConfigSelectionArray {
currentValue: Config.options.background.widgets.clock.cookie.dialNumberStyle currentValue: Config.options.background.widgets.clock.cookie.dialNumberStyle
@@ -270,7 +307,7 @@ ContentPage {
} }
ContentSubsection { ContentSubsection {
visible: Config.options.background.widgets.clock.style === "cookie" visible: settingsClock.cookiePresent
title: Translation.tr("Hour hand") title: Translation.tr("Hour hand")
ConfigSelectionArray { ConfigSelectionArray {
currentValue: Config.options.background.widgets.clock.cookie.hourHandStyle currentValue: Config.options.background.widgets.clock.cookie.hourHandStyle
@@ -303,7 +340,7 @@ ContentPage {
} }
ContentSubsection { ContentSubsection {
visible: Config.options.background.widgets.clock.style === "cookie" visible: settingsClock.cookiePresent
title: Translation.tr("Minute hand") title: Translation.tr("Minute hand")
ConfigSelectionArray { ConfigSelectionArray {
@@ -342,7 +379,7 @@ ContentPage {
} }
ContentSubsection { ContentSubsection {
visible: Config.options.background.widgets.clock.style === "cookie" visible: settingsClock.cookiePresent
title: Translation.tr("Second hand") title: Translation.tr("Second hand")
ConfigSelectionArray { ConfigSelectionArray {
@@ -376,7 +413,7 @@ ContentPage {
} }
ContentSubsection { ContentSubsection {
visible: Config.options.background.widgets.clock.style === "cookie" visible: settingsClock.cookiePresent
title: Translation.tr("Date style") title: Translation.tr("Date style")
ConfigSelectionArray { ConfigSelectionArray {
@@ -148,18 +148,18 @@ ContentPage {
ConfigSwitch { ConfigSwitch {
buttonIcon: "keep" buttonIcon: "keep"
text: Translation.tr('Make icons pinned by default') text: Translation.tr('Make icons pinned by default')
checked: Config.options.bar.tray.invertPinnedItems checked: Config.options.tray.invertPinnedItems
onCheckedChanged: { onCheckedChanged: {
Config.options.bar.tray.invertPinnedItems = checked; Config.options.tray.invertPinnedItems = checked;
} }
} }
ConfigSwitch { ConfigSwitch {
buttonIcon: "colors" buttonIcon: "colors"
text: Translation.tr('Tint icons') text: Translation.tr('Tint icons')
checked: Config.options.bar.tray.monochromeIcons checked: Config.options.tray.monochromeIcons
onCheckedChanged: { onCheckedChanged: {
Config.options.bar.tray.monochromeIcons = checked; Config.options.tray.monochromeIcons = checked;
} }
} }
} }
@@ -334,4 +334,17 @@ ContentPage {
} }
} }
} }
ContentSection {
icon: "tooltip"
title: Translation.tr("Tooltips")
ConfigSwitch {
buttonIcon: "ads_click"
text: Translation.tr("Click to show")
checked: Config.options.bar.tooltips.clickToShow
onCheckedChanged: {
Config.options.bar.tooltips.clickToShow = checked;
}
}
}
} }
@@ -22,7 +22,7 @@ ContentPage {
// Use a nerdfont to see the icons // Use a nerdfont to see the icons
options: ([ options: ([
"󰖳", "", "󰨡", "", "󰌽", "󰣇", "", "", "", "󰖳", "", "󰨡", "", "󰌽", "󰣇", "", "", "",
"", "", "󱄛", "", "", "⌘", "󰀲", "󰟍", "" "", "", "󱄛", "", "", "", "⌘", "󰀲", "󰟍", ""
]).map(icon => { return { ]).map(icon => { return {
displayName: icon, displayName: icon,
value: icon value: icon
@@ -0,0 +1,37 @@
## Waffle
A recreation of Windoes. It's WIP!
- If you install illogical-impulse fully, you can press Super+Alt+W to switch to this style.
- If you're just copying the Quickshell config, run the config as usual (`qs -c ii`) then run `qs -c ii ipc call panelFamily cycle`
## From EWW version to Quickshell
Just a reflection, in case anyone's interested. My blog is probably a better place for this, but it does not exist. Besides, this is going to change as I do more stuff. Currently there's just the bar.
### Improvements
- QtQuick's `Button` has the `{top/bottom/left/right}Inset` properties, so we can have clickable regions expanding beyond the button background for free. With EWW it was annoying to wrap the button content with an `eventbox` that has some padding, then somehow use CSS selectors to make sure hovering effects work. I have to admit, (a large) part of that annoyance was with how bad my copy-pasting coding practice was at the time, but still...
- Fancy effects: Gtk3 CSS does not support transformations. In QtQuick we can smack `rotation` and `scale` almost everywhere, so it's simple to make bouncy icons and rotating chevrons
- Quickshell provides a system tray service (EWW does now but didn't at the time I created the EWW Windoes version), so now there's no Waybar needed for the tray.
- QtQuick has `Loader`s, so we can have this live-switchable from the main style without killing the widget system, moving styles to the correct folder, and relaunching.
- This time my computer is powerful enough to run a VM, so I don't have to occasionally reboot to take quick screenshots for reference. I try to make everything pixel-perfect so this is necessary. Speaking about pixel-perfectness, in the EWW version I hardcoded sizes, but this time I'm still doing that (lol), BUT that's normal and not a problem because Qt has the `QT_SCALE_FACTOR` env var for scaling. (Please feel free to prove me wrong in saying Gtk3 doesn't have that magic)
### Challenges
- Qt is not Gtk and definitely not React
- We don't get directional border on QtQuick `Rectangle`s like in CSS. I was able to get around this with manual drawing, but it was a bit more work
- Fluent Icons is difficult to use, compared to Material Symbols
- No React, so no clean use via a library.
- If we use the font, there's no proper, searchable **codepoint** cheatsheet like Nerd Fonts, and there's no ligatures
- I resorted to downloading individual SVGs. Not that nice, but it's better than scanning the whole table of icons every time I want one. For this we have fluenticon.com and fluenticons.co, but icons are awkwardly named and there's no alias. Why is the reload/refresh icon called "arrow-sync"? Well, the name is not misleading, but arguably reload/refresh are more common actions. From Fluent Design's [page on Iconography](https://fluent2.microsoft.design/iconography):
> Fluent system icons are literal metaphors and are named for the shape or object they represent, not the functionality they provide
"sync" is functionality.
@@ -0,0 +1,77 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
WBarAttachedPanelContent {
id: root
contentItem: ColumnLayout {
anchors.centerIn: parent
spacing: 0
Rectangle {
Layout.fillHeight: true
Layout.fillWidth: true
topLeftRadius: root.border.radius - root.border.border.width
topRightRadius: topLeftRadius
color: Looks.colors.bgPanelBody
implicitWidth: 360
implicitHeight: 380
}
Rectangle {
Layout.fillHeight: false
Layout.fillWidth: true
color: Looks.colors.bgPanelSeparator
implicitHeight: 1
}
Rectangle {
Layout.fillHeight: false
Layout.fillWidth: true
bottomLeftRadius: root.border.radius - root.border.border.width
bottomRightRadius: bottomLeftRadius
color: Looks.colors.bgPanelFooter
implicitWidth: 360
implicitHeight: 47
// Battery button
WPanelFooterButton {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 12
contentItem: Row {
spacing: 4
FluentIcon {
anchors.verticalCenter: parent.verticalCenter
icon: WIcons.batteryIcon
}
WText {
anchors.verticalCenter: parent.verticalCenter
text: `${Math.round(Battery.percentage * 100) || 0}%`
}
}
}
// Settings button
WPanelFooterButton {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 12
contentItem: FluentIcon {
icon: "settings"
}
}
}
}
}
@@ -0,0 +1,85 @@
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
Scope {
id: root
Connections {
target: GlobalStates
function onSidebarLeftOpenChanged() {
if (GlobalStates.sidebarLeftOpen) barLoader.active = true;
}
}
Loader {
id: barLoader
active: GlobalStates.sidebarLeftOpen
sourceComponent: PanelWindow {
id: panelWindow
exclusiveZone: 0
WlrLayershell.namespace: "quickshell:actionCenter"
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
color: "transparent"
anchors {
bottom: Config.options.waffles.bar.bottom
top: !Config.options.waffles.bar.bottom
right: true
}
implicitWidth: content.implicitWidth + content.visualMargin * 2
implicitHeight: content.implicitHeight + content.visualMargin * 2
HyprlandFocusGrab {
id: focusGrab
active: true
windows: [panelWindow]
onCleared: content.close();
}
Connections {
target: GlobalStates
function onSidebarLeftOpenChanged() {
if (!GlobalStates.sidebarLeftOpen) content.close();
}
}
ActionCenterContent {
id: content
anchors.centerIn: parent
onClosed: {
barLoader.active = false;
GlobalStates.sidebarLeftOpen = false;
}
}
}
}
function toggleOpen() {
GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen;
}
IpcHandler {
target: "sidebarLeft"
function toggle() {
root.toggleOpen();
}
}
GlobalShortcut {
name: "sidebarLeftToggle"
description: "Toggles left sidebar on press"
onPressed: root.toggleOpen();
}
}
@@ -17,10 +17,12 @@ BarButton {
rightInset: 2 rightInset: 2
implicitWidth: height - topInset - bottomInset + leftInset + rightInset implicitWidth: height - topInset - bottomInset + leftInset + rightInset
property real pressedScale: 5/6
onDownChanged: { onDownChanged: {
scaleAnim.duration = root.down ? 150 : 200 scaleAnim.duration = root.down ? 150 : 200
scaleAnim.easing.bezierCurve = root.down ? Looks.transition.easing.bezierCurve.easeIn : Looks.transition.easing.bezierCurve.easeOut scaleAnim.easing.bezierCurve = root.down ? Looks.transition.easing.bezierCurve.easeIn : Looks.transition.easing.bezierCurve.easeOut
contentItem.scale = root.down ? 5/6 : 1 // If/When we do dragging, the scale is 1.25 contentItem.scale = root.down ? root.pressedScale : 1 // If/When we do dragging, the scale is 1.25
} }
background: Item { background: Item {
@@ -45,9 +47,7 @@ BarButton {
anchors.fill: parent anchors.fill: parent
anchors.rightMargin: 5 anchors.rightMargin: 5
active: root.multiple active: root.multiple
sourceComponent: BackgroundAcrylicRectangle { sourceComponent: BackgroundAcrylicRectangle {}
}
} }
} }
@@ -75,7 +75,7 @@ BarButton {
component BackgroundAcrylicRectangle: AcrylicRectangle { component BackgroundAcrylicRectangle: AcrylicRectangle {
shiny: ((root.hovered && !root.down) || root.checked) shiny: ((root.hovered && !root.down) || root.checked)
color: root.colBackground color: root.color
border.width: 1 border.width: 1
border.color: root.colBackgroundBorder border.color: root.colBackgroundBorder
@@ -13,6 +13,8 @@ Kirigami.Icon {
property real implicitSize: 26 property real implicitSize: 26
implicitWidth: implicitSize implicitWidth: implicitSize
implicitHeight: implicitSize implicitHeight: implicitSize
animated: true
roundToIconSize: false roundToIconSize: false
fallback: root.iconName fallback: root.iconName
source: tryCustomIcon ? `${Looks.iconsPath}/${root.iconName}${!root.separateLightDark ? "" : Looks.dark ? "-dark" : "-light"}.svg` : fallback source: tryCustomIcon ? `${Looks.iconsPath}/${root.iconName}${!root.separateLightDark ? "" : Looks.dark ? "-dark" : "-light"}.svg` : fallback
@@ -8,11 +8,14 @@ import qs.modules.waffle.looks
Button { Button {
id: root id: root
signal altAction() property var altAction: () => {}
signal middleClickAction() property var middleClickAction: () => {}
property color colBackground property color colBackground: ColorUtils.transparentize(Looks.colors.bg1)
property color colBackgroundHover: Looks.colors.bg1Hover
property color colBackgroundActive: Looks.colors.bg1Active
property color colBackgroundBorder property color colBackgroundBorder
property color color
Layout.fillHeight: true Layout.fillHeight: true
topInset: 4 topInset: 4
bottomInset: 4 bottomInset: 4
@@ -37,16 +40,16 @@ Button {
} }
} }
colBackground: { colBackgroundBorder: ColorUtils.transparentize(Looks.colors.bg1Border, (root.checked || root.hovered) ? Looks.contentTransparency : 1)
color: {
if (root.down) { if (root.down) {
return Looks.colors.bg1Active return root.colBackgroundActive
} else if ((root.hovered && !root.down) || root.checked) { } else if ((root.hovered && !root.down) || root.checked) {
return Looks.colors.bg1Hover return root.colBackgroundHover
} else { } else {
return ColorUtils.transparentize(Looks.colors.bg1) return root.colBackground
} }
} }
colBackgroundBorder: ColorUtils.transparentize(Looks.colors.bg1Border, root.checked ? Looks.contentTransparency : 1)
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
@@ -66,7 +69,8 @@ Button {
background: AcrylicRectangle { background: AcrylicRectangle {
shiny: ((root.hovered && !root.down) || root.checked) shiny: ((root.hovered && !root.down) || root.checked)
color: root.colBackground color: root.color
radius: Looks.radius.medium
border.width: 1 border.width: 1
border.color: root.colBackgroundBorder border.color: root.colBackgroundBorder
@@ -0,0 +1,41 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.waffle.looks
import qs.modules.waffle.bar
BarButton {
id: root
property alias iconName: iconContent.icon
property alias iconSource: iconContent.source
property alias iconSize: iconContent.implicitSize
property alias iconRotation: iconContent.rotation
property alias iconMonochrome: iconContent.monochrome
property alias iconScale: iconContent.scale
property alias tooltipText: tooltip.text
property alias overlayingItems: iconContent.data
implicitWidth: 32
contentItem: Item {
anchors.centerIn: parent
implicitWidth: iconContent.implicitWidth
implicitHeight: iconContent.implicitHeight
FluentIcon {
id: iconContent
anchors.centerIn: parent
implicitSize: 16
icon: root.iconName
monochrome: false
}
}
BarToolTip {
id: tooltip
extraVisibleCondition: root.shouldShowTooltip && text !== ""
}
}
@@ -0,0 +1,59 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Hyprland
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
BarPopup {
id: root
default property var menuData
property var model: [
{ iconName: "start-here", text: "Start", action: () => {print("hello")} },
{ type : "separator" },
]
readonly property bool hasIcons: model.some(item => item.iconName !== undefined && item.iconName !== "")
padding: 2
contentItem: ColumnLayout {
anchors.centerIn: parent
spacing: 0
Repeater {
model: root.model
delegate: DelegateChooser {
role: "type"
DelegateChoice {
roleValue: "separator"
Rectangle {
Layout.topMargin: 2
Layout.bottomMargin: 2
Layout.fillWidth: true
implicitHeight: 1
color: Looks.colors.bg0Border
}
}
DelegateChoice {
roleValue: undefined
WButton {
id: btn
Layout.fillWidth: true
required property var modelData
forceShowIcon: root.hasIcons
icon.name: modelData.iconName ? modelData.iconName : ""
monochromeIcon: modelData.monochromeIcon ?? true
text: modelData.text ? modelData.text : ""
onClicked: {
if (modelData.action) modelData.action();
root.close();
}
}
}
}
}
}
}
@@ -0,0 +1,131 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Hyprland
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
Loader {
id: root
required property var contentItem
property real padding: Looks.radius.large - Looks.radius.medium
property bool noSmoothClosing: !Config.options.waffles.smootherAnimations
property bool closeOnFocusLost: true
signal focusCleared()
property Item anchorItem: parent
property real visualMargin: 12
readonly property bool barAtBottom: Config.options.waffles.bar.bottom
property real ambientShadowWidth: 1
onFocusCleared: {
if (!root.closeOnFocusLost) return;
root.close()
}
function grabFocus() { // Doesn't work
item.grabFocus();
}
function close() {
item.close();
}
function updateAnchor() {
item?.anchor.updateAnchor();
}
active: false
visible: active
sourceComponent: PopupWindow {
id: popupWindow
visible: true
Component.onCompleted: {
openAnim.start();
}
anchor {
adjustment: PopupAdjustment.ResizeY | PopupAdjustment.SlideX
item: root.anchorItem
gravity: root.barAtBottom ? Edges.Top : Edges.Bottom
edges: root.barAtBottom ? Edges.Top : Edges.Bottom
}
HyprlandFocusGrab {
id: focusGrab
active: true
windows: [popupWindow]
onCleared: root.focusCleared();
}
function close() {
if (root.noSmoothClosing) root.active = false;
else closeAnim.start();
}
function grabFocus() {
focusGrab.active = true; // Doesn't work
}
implicitWidth: realContent.implicitWidth + (root.ambientShadowWidth * 2) + (root.visualMargin * 2)
implicitHeight: realContent.implicitHeight + (root.ambientShadowWidth * 2) + (root.visualMargin * 2)
property real sourceEdgeMargin: -implicitHeight
PropertyAnimation {
id: openAnim
target: popupWindow
property: "sourceEdgeMargin"
to: (root.ambientShadowWidth + root.visualMargin)
duration: 200
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
}
SequentialAnimation {
id: closeAnim
PropertyAnimation {
target: popupWindow
property: "sourceEdgeMargin"
to: -implicitHeight
duration: 150
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeOut
}
ScriptAction {
script: {
root.active = false;
}
}
}
color: "transparent"
WAmbientShadow {
target: realContent
}
Rectangle {
id: realContent
z: 1
anchors {
left: parent.left
right: parent.right
top: root.barAtBottom ? undefined : parent.top
bottom: root.barAtBottom ? parent.bottom : undefined
margins: root.ambientShadowWidth + root.visualMargin
// Opening anim
bottomMargin: root.barAtBottom ? popupWindow.sourceEdgeMargin : (root.ambientShadowWidth + root.visualMargin)
topMargin: root.barAtBottom ? (root.ambientShadowWidth + root.visualMargin) : popupWindow.sourceEdgeMargin
}
color: Looks.colors.bg1
radius: Looks.radius.large
// test
implicitWidth: root.contentItem.implicitWidth + (root.padding * 2)
implicitHeight: root.contentItem.implicitHeight + (root.padding * 2)
children: [root.contentItem]
}
}
}
@@ -9,9 +9,10 @@ import qs.modules.waffle.looks
AppButton { AppButton {
id: root id: root
iconName: "system-search" iconName: checked ? "system-search-checked" : "system-search"
separateLightDark: true separateLightDark: true
checked: GlobalStates.overviewOpen
onClicked: { onClicked: {
GlobalStates.overviewOpen = !GlobalStates.overviewOpen; // For now... GlobalStates.overviewOpen = !GlobalStates.overviewOpen; // For now...
} }
@@ -1,6 +1,7 @@
import QtQuick import QtQuick
import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import org.kde.kirigami as Kirigami import Quickshell
import qs import qs
import qs.services import qs.services
import qs.modules.common import qs.modules.common
@@ -10,7 +11,7 @@ AppButton {
id: root id: root
leftInset: Config.options.waffles.bar.leftAlignApps ? 12 : 0 leftInset: Config.options.waffles.bar.leftAlignApps ? 12 : 0
iconName: "start-here" iconName: down ? "start-here-pressed" : "start-here"
onClicked: { onClicked: {
GlobalStates.overviewOpen = !GlobalStates.overviewOpen; // For now... GlobalStates.overviewOpen = !GlobalStates.overviewOpen; // For now...
@@ -21,4 +22,45 @@ AppButton {
text: Translation.tr("Start") text: Translation.tr("Start")
extraVisibleCondition: root.shouldShowTooltip extraVisibleCondition: root.shouldShowTooltip
} }
altAction: () => {
contextMenu.active = true;
}
BarMenu {
id: contextMenu
model: [
{
text: Translation.tr("Terminal"),
action: () => {
Quickshell.execDetached(["bash", "-c", Config.options.apps.terminal]);
}
},
{
text: Translation.tr("Task Manager"),
action: () => {
Quickshell.execDetached(["bash", "-c", Config.options.apps.taskManager]);
}
},
{
text: Translation.tr("Settings"),
action: () => {
Quickshell.execDetached(["qs", "-p", Quickshell.shellPath("settings.qml")]);
}
},
{
text: Translation.tr("File Explorer"),
action: () => {
Qt.openUrlExternally(Directories.home);
}
},
{
text: Translation.tr("Search"),
action: () => {
Quickshell.execDetached(["qs", "-p", Quickshell.shellPath(""), "ipc", "call", "overview", "toggle"]);
}
},
]
}
} }
@@ -8,9 +8,9 @@ import qs.modules.waffle.looks
BarButton { BarButton {
id: root id: root
checked: GlobalStates.sidebarRightOpen checked: GlobalStates.sidebarLeftOpen
onClicked: { onClicked: {
GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen; // For now... GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen;
} }
contentItem: Item { contentItem: Item {
@@ -85,11 +85,13 @@ BarButton {
BarToolTip { BarToolTip {
extraVisibleCondition: root.shouldShowTooltip && volumeHoverArea.containsMouse extraVisibleCondition: root.shouldShowTooltip && volumeHoverArea.containsMouse
text: Translation.tr("Speakers (%1): %2") // text: Translation.tr("Speakers (%1): %2") //
.arg(Audio.sink?.nickname || Audio.sink?.description || Translation.tr("Unknown")) // .arg(Audio.sink?.nickname || Audio.sink?.description || Translation.tr("Unknown")) //
.arg(`${Math.round(Audio.sink?.audio.volume * 100) || 0}%`) // .arg(Audio.sink?.audio.muted ? Translation.tr("Muted") : `${Math.round(Audio.sink?.audio.volume * 100) || 0}%`) //
} }
BarToolTip { BarToolTip {
extraVisibleCondition: root.shouldShowTooltip && batteryHoverArea.containsMouse extraVisibleCondition: root.shouldShowTooltip && batteryHoverArea.containsMouse
text: Translation.tr("Battery: %1").arg(`${Math.round(Battery.percentage * 100) || 0}%`) text: Translation.tr("Battery: %1%2") //
.arg(`${Math.round(Battery.percentage * 100) || 0}%`) //
.arg(Battery.isPluggedIn ? (" " + Translation.tr("(Plugged in)")) : "")
} }
} }
@@ -9,7 +9,8 @@ import qs.modules.waffle.looks
AppButton { AppButton {
id: root id: root
iconName: "task-view" iconName: (down && !checked) ? "task-view-pressed" : "task-view"
pressedScale: checked ? 5/6 : 1
separateLightDark: true separateLightDark: true
checked: GlobalStates.overviewOpen checked: GlobalStates.overviewOpen
@@ -0,0 +1,33 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.waffle.looks
import qs.modules.waffle.bar.tray
BarIconButton {
id: root
visible: Updates.updateAdvised || Updates.updateStronglyAdvised
padding: 4
iconName: "arrow-sync"
iconSize: 20 // Needed because the icon appears to have some padding
tooltipText: Translation.tr("Get the latest features and security improvements with\nthe newest feature update.\n\n%1 packages").arg(Updates.count)
onClicked: {
Quickshell.execDetached(["bash", "-c", Config.options.apps.update]);
}
overlayingItems: Rectangle {
anchors {
right: parent.right
bottom: parent.bottom
margins: 1
}
implicitWidth: 8
implicitHeight: implicitWidth
radius: height / 2
color: Updates.updateStronglyAdvised ? Looks.colors.warning : Looks.colors.accent
}
}
@@ -9,9 +9,8 @@ import qs.modules.common
import qs.modules.common.widgets import qs.modules.common.widgets
Scope { Scope {
id: bar id: root
property bool showBarBackground: Config.options.bar.showBackground
LazyLoader { LazyLoader {
id: barLoader id: barLoader
active: GlobalStates.barOpen && !GlobalStates.screenLocked active: GlobalStates.barOpen && !GlobalStates.screenLocked
@@ -4,6 +4,7 @@ import qs.modules.common
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.modules.waffle.looks import qs.modules.waffle.looks
import qs.modules.waffle.bar.tasks import qs.modules.waffle.bar.tasks
import qs.modules.waffle.bar.tray
Rectangle { Rectangle {
id: root id: root
@@ -68,6 +69,8 @@ Rectangle {
shown: Config.options.waffles.bar.leftAlignApps shown: Config.options.waffles.bar.leftAlignApps
sourceComponent: WidgetsButton {} sourceComponent: WidgetsButton {}
} }
Tray {}
UpdatesButton {}
SystemButton {} SystemButton {}
TimeButton {} TimeButton {}
} }
@@ -18,6 +18,11 @@ AppButton {
onClicked: { onClicked: {
GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen
} }
onDownChanged: {
scaleAnim.duration = root.down ? 150 : 200
scaleAnim.easing.bezierCurve = root.down ? Looks.transition.easing.bezierCurve.easeIn : Looks.transition.easing.bezierCurve.easeOut
iconWidget.scale = root.down ? 5/6 : 1 // If/When we do dragging, the scale is 1.25
}
contentItem: Item { contentItem: Item {
anchors { anchors {
@@ -41,6 +46,13 @@ AppButton {
id: iconWidget id: iconWidget
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
iconName: root.iconName iconName: root.iconName
Behavior on scale {
NumberAnimation {
id: scaleAnim
easing.type: Easing.BezierSpline
}
}
} }
Column { Column {
@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.services import qs.services
import qs.modules.common import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks import qs.modules.waffle.looks
import qs.modules.waffle.bar import qs.modules.waffle.bar
import Quickshell import Quickshell
@@ -16,6 +17,7 @@ AppButton {
property bool hasWindows: appEntry.toplevels.length > 0 property bool hasWindows: appEntry.toplevels.length > 0
signal hoverPreviewRequested() signal hoverPreviewRequested()
signal hoverPreviewDismissed()
multiple: appEntry.toplevels.length > 1 multiple: appEntry.toplevels.length > 1
checked: active checked: active
@@ -37,12 +39,18 @@ AppButton {
} }
} }
onMiddleClickAction: { middleClickAction: () => {
if (root.desktopEntry) { if (root.desktopEntry) {
desktopEntry.execute() desktopEntry.execute()
} }
} }
altAction: () => {
root.hoverPreviewDismissed()
root.hoverTimer.stop()
contextMenu.active = true;
}
// Active indicator // Active indicator
Rectangle { Rectangle {
id: activeIndicator id: activeIndicator
@@ -74,4 +82,44 @@ AppButton {
extraVisibleCondition: root.shouldShowTooltip && !root.hasWindows extraVisibleCondition: root.shouldShowTooltip && !root.hasWindows
text: desktopEntry ? desktopEntry.name : appEntry.appId text: desktopEntry ? desktopEntry.name : appEntry.appId
} }
BarMenu {
id: contextMenu
model: [
...((root.desktopEntry?.actions.length > 0) ? root.desktopEntry.actions.map(action =>({
iconName: action.icon,
text: action.name,
action: () => {
action.execute()
}
})).concat({ type: "separator" }) : []),
{
iconName: root.iconName,
text: root.desktopEntry ? root.desktopEntry.name : StringUtils.toTitleCase(appEntry.appId),
monochromeIcon: false,
action: () => {
if (root.desktopEntry) {
root.desktopEntry.execute()
}
}
},
{
iconName: root.appEntry.pinned ? "pin-off" : "pin",
text: root.appEntry.pinned ? qsTr("Unpin from taskbar") : qsTr("Pin to taskbar"),
action: () => {
TaskbarApps.togglePin(root.appEntry.appId);
}
},
...(root.appEntry.toplevels.length > 0 ? [{
iconName: "dismiss",
text: root.multiple ? qsTr("Close all windows") : qsTr("Close window"),
action: () => {
for (let toplevel of root.appEntry.toplevels) {
toplevel.close();
}
}
}] : []),
]
}
} }
@@ -16,7 +16,7 @@ PopupWindow {
property Item anchorItem property Item anchorItem
//////////////////// Functions //////////////////// //////////////////// Functions ////////////////////
function close() { function close() { // Closing doesn't animate, not sure if they're just lazy or it's intentional
marginBehavior.enabled = false; marginBehavior.enabled = false;
root.visible = false; root.visible = false;
} }
@@ -36,7 +36,7 @@ PopupWindow {
///////////////////// Internals ///////////////////// ///////////////////// Internals /////////////////////
readonly property bool bottom: Config.options.waffles.bar.bottom readonly property bool bottom: Config.options.waffles.bar.bottom
property real visualMargin: 12 property real visualMargin: 12
property alias ambientShadowWidth: ambientShadow.border.width property real ambientShadowWidth: 1
visible: false visible: false
color: "transparent" color: "transparent"
@@ -64,16 +64,8 @@ PopupWindow {
hoverEnabled: true hoverEnabled: true
// Shadow // Shadow
Rectangle { WAmbientShadow {
id: ambientShadow target: contentItem
anchors {
fill: contentItem
margins: -border.width
}
border.color: ColorUtils.transparentize(Looks.colors.bg0Border, Looks.shadowTransparency)
border.width: 1
color: "transparent"
radius: Looks.radius.large + border.width
} }
Rectangle { Rectangle {
@@ -17,10 +17,17 @@ MouseArea {
previewPopup.show(appEntry, button); previewPopup.show(appEntry, button);
} }
Behavior on implicitWidth {
animation: Looks.transition.move.createObject(this)
}
// Apps row // Apps row
RowLayout { RowLayout {
id: row id: row
anchors.fill: parent anchors {
top: parent.top
bottom: parent.bottom
}
spacing: 0 spacing: 0
Repeater { Repeater {
@@ -36,6 +43,9 @@ MouseArea {
onHoverPreviewRequested: { onHoverPreviewRequested: {
root.showPreviewPopup(appEntry, this) root.showPreviewPopup(appEntry, this)
} }
onHoverPreviewDismissed: {
previewPopup.close()
}
} }
} }
} }
@@ -46,4 +56,5 @@ MouseArea {
tasksHovered: root.containsMouse tasksHovered: root.containsMouse
anchor.window: root.QsWindow.window anchor.window: root.QsWindow.window
} }
} }
@@ -0,0 +1,118 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Qt.labs.synchronizer
import Quickshell
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.waffle.looks
import qs.modules.waffle.bar
RowLayout {
id: root
property bool overflowOpen: false
property bool dragging: false
Layout.fillHeight: true
spacing: 0
BarIconButton {
id: overflowButton
visible: (TrayService.unpinnedItems.length > 0 || root.dragging)
checked: root.overflowOpen
iconName: "chevron-down"
iconMonochrome: true
iconRotation: (Config.options.waffles.bar.bottom ? 180 : 0) + (root.overflowOpen ? 180 : 0)
Behavior on iconRotation {
animation: Looks.transition.rotate.createObject(this)
}
onClicked: {
root.overflowOpen = !root.overflowOpen;
}
TrayOverflowMenu {
id: trayOverflowLayout
Synchronizer on active {
property alias source: root.overflowOpen
}
}
BarToolTip {
extraVisibleCondition: overflowButton.shouldShowTooltip
text: qsTr("Show hidden icons")
}
DropArea {
id: pinDropArea
anchors.fill: parent
property bool willPin: false
onEntered: willPin = true
onExited: willPin = false
}
}
Repeater {
model: ScriptModel {
values: TrayService.pinnedItems
}
delegate: TrayButton {
id: trayButton
required property var modelData
item: modelData
property real initialX
property real initialY
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: parent
drag.axis: Drag.XAxis
drag.threshold: 2
onPressed: event => {
trayButton.Drag.hotSpot.x = event.x;
trayButton.initialX = trayButton.x;
root.dragging = true;
trayButton.Drag.active = true;
}
onPositionChanged: {
pinTooltip.updateAnchor();
}
onReleased: {
if (!dragArea.drag.active) {
trayButton.click();
} else {
if (pinDropArea.containsDrag && pinDropArea.willPin) {
// Quickshell would crash if we don't hide this item first. Took me fucking 3 hours to figure out...
trayButton.visible = false;
TrayService.togglePin(trayButton.item.id);
pinDropArea.willPin = false;
} else {
trayButton.x = trayButton.initialX;
}
}
trayButton.Drag.active = false;
root.dragging = false;
}
}
BarToolTip {
id: pinTooltip
extraVisibleCondition: trayButton.Drag.active && pinDropArea.containsDrag && pinDropArea.willPin
realContentHorizontalPadding: 6
realContentVerticalPadding: 6
realContentItem: FluentIcon {
anchors.centerIn: parent
icon: "pin-off"
implicitSize: 18
}
}
}
}
}
@@ -0,0 +1,52 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.SystemTray
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.waffle.looks
import qs.modules.waffle.bar
BarIconButton {
id: root
required property SystemTrayItem item
property alias menuOpen: menu.visible
readonly property bool barAtBottom: Config.options.waffles.bar.bottom
iconSource: item.icon
iconScale: 0
Component.onCompleted: {
root.iconScale = 1
}
Behavior on iconScale {
animation: Looks.transition.enter.createObject(this)
}
onClicked: {
item.activate();
}
altAction: () => {
if (item.hasMenu) menu.open()
}
// This is lazy, but it's not like tray menus on Windoes are consistent...
// TODO: Figure out how to do cascading menus then use a custom menu
QsMenuAnchor {
id: menu
menu: root.item.menu
anchor {
adjustment: PopupAdjustment.ResizeY | PopupAdjustment.SlideX
item: root
gravity: root.barAtBottom ? Edges.Top : Edges.Bottom
edges: root.barAtBottom ? Edges.Top : Edges.Bottom
}
}
BarToolTip {
extraVisibleCondition: root.shouldShowTooltip && !root.Drag.active
text: TrayService.getTooltipForItem(root.item)
}
}
@@ -0,0 +1,124 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Hyprland
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
import qs.modules.waffle.bar
BarPopup {
id: root
closeOnFocusLost: false
onFocusCleared: {
const hasMenuOpen = contentItem.children.some(c => (c.menuOpen));
if (!hasMenuOpen)
root.close();
else
root.grabFocus();
}
contentItem: Item {
id: contentItem
anchors.centerIn: parent
implicitWidth: contentGrid.implicitWidth
implicitHeight: contentGrid.implicitHeight
GridLayout {
id: contentGrid
anchors.centerIn: parent
rows: Math.floor(Math.sqrt(TrayService.unpinnedItems.length))
columns: Math.ceil(TrayService.unpinnedItems.length / rows)
columnSpacing: 0
rowSpacing: 0
Repeater {
model: ScriptModel {
values: TrayService.unpinnedItems
onValuesChanged: {
root.updateAnchor();
if (values.length === 0) {
root.close();
}
}
}
delegate: TrayButton {
id: trayButton
required property var modelData
item: modelData
topInset: 0
bottomInset: 0
implicitWidth: 40
implicitHeight: 40
colBackground: ColorUtils.transparentize(Looks.colors.bg2)
colBackgroundHover: Looks.colors.bg2Hover
colBackgroundActive: Looks.colors.bg2Active
onMenuOpenChanged: {
// The overflow menu should only be closed when the user clicks outside
// However the focus grab refuses to reactivate, so we can't have that
// But most of the time the user dismisses the menu by clicking outside anyway,
// so this is acceptable.
if (!menuOpen) {
root.close();
}
}
property real initialX
property real initialY
Behavior on x {
animation: Looks.transition.move.createObject(this)
}
Behavior on y {
animation: Looks.transition.move.createObject(this)
}
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: parent
drag.threshold: 2
onPressed: event => {
trayButton.Drag.hotSpot.x = event.x;
trayButton.Drag.hotSpot.y = event.y;
trayButton.initialX = trayButton.x;
trayButton.initialY = trayButton.y;
trayButton.Drag.active = true;
}
onReleased: {
if (!dragArea.drag.active) {
trayButton.click();
} else {
if (!unpinDropArea.containsDrag && unpinDropArea.willUnpin) {
// Quickshell would crash if we don't hide this item first. Took me fucking 3 hours to figure out...
trayButton.visible = false;
TrayService.togglePin(trayButton.item.id);
unpinDropArea.willUnpin = false;
} else {
trayButton.x = trayButton.initialX;
trayButton.y = trayButton.initialY;
}
}
trayButton.Drag.active = false;
}
}
}
}
}
DropArea {
id: unpinDropArea
anchors.fill: parent
property bool willUnpin: false
onEntered: willUnpin = false
onExited: willUnpin = true
}
}
}
@@ -6,6 +6,7 @@ import qs.modules.waffle.looks
Kirigami.Icon { Kirigami.Icon {
id: root id: root
required property string icon required property string icon
property alias monochrome: root.isMask
// Should be 16, but it appears the icons have some padding, // Should be 16, but it appears the icons have some padding,
// Unlike the Windows-only Segoe UI icons, the open source FluentUI ones are hella small // Unlike the Windows-only Segoe UI icons, the open source FluentUI ones are hella small
property int implicitSize: 20 property int implicitSize: 20
@@ -17,9 +17,12 @@ Singleton {
property real backgroundTransparency: 0.17 property real backgroundTransparency: 0.17
property real contentTransparency: 0.25 property real contentTransparency: 0.25
property real shadowTransparency: 0.6
colors: QtObject { colors: QtObject {
id: colors id: colors
property color ambientShadow: ColorUtils.transparentize("#000000", 0.75)
property color bgPanelFooter: root.dark ? "#1C1C1C" : "#EEEEEE"
property color bgPanelBody: root.dark ? "#242424" : "#F2F2F2"
property color bgPanelSeparator: root.dark ? "#191919" : "#E0E0E0"
property color bg0: root.dark ? "#1C1C1C" : "#EEEEEE" property color bg0: root.dark ? "#1C1C1C" : "#EEEEEE"
property color bg0Border: root.dark ? "#404040" : "#BEBEBE" property color bg0Border: root.dark ? "#404040" : "#BEBEBE"
property color bg1: root.dark ? "#2C2C2C" : "#F7F7F7" property color bg1: root.dark ? "#2C2C2C" : "#F7F7F7"
@@ -34,6 +37,7 @@ Singleton {
property color fg1: root.dark ? "#D1D1D1" : "#626262" property color fg1: root.dark ? "#D1D1D1" : "#626262"
property color danger: "#C42B1C" property color danger: "#C42B1C"
property color dangerActive: "#B62D1F" property color dangerActive: "#B62D1F"
property color warning: "#FF9900"
// property color accent: root.dark ? "#A5C6D8" : "#5377A3" // property color accent: root.dark ? "#A5C6D8" : "#5377A3"
property color accent: Appearance.m3colors.m3primary property color accent: Appearance.m3colors.m3primary
property color accentUnfocused: root.dark ? "#989898" : "#848484" property color accentUnfocused: root.dark ? "#989898" : "#848484"
@@ -61,7 +65,7 @@ Singleton {
} }
property QtObject pixelSize: QtObject { property QtObject pixelSize: QtObject {
property real normal: 11 property real normal: 11
property real large: 15 property real large: 14
} }
} }
@@ -115,6 +119,14 @@ Singleton {
} }
} }
property Component rotate: Component {
NumberAnimation {
duration: 170
easing.type: Easing.BezierSpline
easing.bezierCurve: transition.easing.bezierCurve.easeInOut
}
}
property Component anchor: Component { property Component anchor: Component {
AnchorAnimation { AnchorAnimation {
duration: 160 duration: 160
@@ -0,0 +1,25 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Hyprland
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
Rectangle {
id: root
required property var target
z: 0
anchors {
fill: target
margins: -border.width
}
border.color: Looks.colors.ambientShadow
border.width: 1
color: "transparent"
radius: target.radius + border.width
}
@@ -0,0 +1,79 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.waffle.looks
Item {
id: root
signal closed()
property alias border: borderRect
required default property Item contentItem
property real visualMargin: 12
function close() {
closeAnim.start();
}
readonly property bool barAtBottom: Config.options.waffles.bar.bottom
implicitHeight: borderRect.implicitHeight
implicitWidth: borderRect.implicitWidth
Rectangle {
id: borderRect
color: "transparent"
radius: Looks.radius.large
border.color: Looks.colors.bg2Border
border.width: 1
implicitWidth: contentItem.implicitWidth + border.width * 2
implicitHeight: contentItem.implicitHeight + border.width * 2
children: [root.contentItem]
anchors {
left: parent.left
right: parent.right
top: root.barAtBottom ? undefined : parent.top
bottom: root.barAtBottom ? parent.bottom : undefined
// Opening anim
bottomMargin: root.barAtBottom ? sourceEdgeMargin : 0
topMargin: root.barAtBottom ? 0 : sourceEdgeMargin
}
Component.onCompleted: {
openAnim.start();
}
property real sourceEdgeMargin: -(implicitHeight + root.visualMargin)
PropertyAnimation {
id: openAnim
target: borderRect
property: "sourceEdgeMargin"
to: 0
duration: 200
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
}
SequentialAnimation {
id: closeAnim
PropertyAnimation {
target: borderRect
property: "sourceEdgeMargin"
to: -(implicitHeight + root.visualMargin)
duration: 150
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeOut
}
ScriptAction {
script: {
root.closed();
}
}
}
}
}
@@ -0,0 +1,95 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
// Generic button with background
Button {
id: root
property color colBackgroundHover: Looks.colors.bg2Hover
property color colBackgroundActive: Looks.colors.bg2Active
property color colBackground: ColorUtils.transparentize(Looks.colors.bg1)
property alias monochromeIcon: buttonIcon.monochrome
property bool forceShowIcon: false
property var altAction: () => {}
property var middleClickAction: () => {}
property real inset: 2
topInset: inset
bottomInset: inset
leftInset: inset
rightInset: inset
horizontalPadding: 10
verticalPadding: 6
implicitHeight: contentItem.implicitHeight + verticalPadding * 2
implicitWidth: contentItem.implicitWidth + horizontalPadding * 2
background: Rectangle {
radius: Looks.radius.medium
color: {
if (root.down) {
return root.colBackgroundActive;
} else if ((root.hovered && !root.down) || root.checked) {
return root.colBackgroundHover;
} else {
return root.colBackground;
}
}
Behavior on color {
animation: Looks.transition.color.createObject(this)
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton | Qt.MiddleButton
onClicked: (event) => {
if (event.button === Qt.LeftButton) root.clicked();
if (event.button === Qt.RightButton) root.altAction();
if (event.button === Qt.MiddleButton) root.middleClickAction();
}
}
contentItem: Item {
anchors {
fill: parent
margins: root.inset
}
implicitWidth: contentLayout.implicitWidth
implicitHeight: contentLayout.implicitHeight
RowLayout {
id: contentLayout
anchors {
fill: parent
leftMargin: root.horizontalPadding
rightMargin: root.horizontalPadding
}
spacing: 12
FluentIcon {
id: buttonIcon
visible: root.icon.name !== "" || root.forceShowIcon
monochrome: true
implicitSize: 16
Layout.leftMargin: 6
Layout.fillWidth: false
Layout.alignment: Qt.AlignVCenter
icon: root.icon.name
}
WText {
Layout.rightMargin: 12
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
text: root.text
horizontalAlignment: Text.AlignLeft
font {
pixelSize: Looks.font.pixelSize.large
}
}
}
}
}
@@ -0,0 +1,32 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
Button {
id: root
implicitHeight: 36
property color colBackground: ColorUtils.transparentize(Looks.colors.bg1)
property color colBackgroundHover: Looks.colors.bg1Hover
property color colBackgroundActive: Looks.colors.bg1Active
property color color
property color colForeground: Looks.colors.fg
color: {
if (root.down) {
return root.colBackgroundActive
} else if ((root.hovered && !root.down) || root.checked) {
return root.colBackgroundHover
} else {
return root.colBackground
}
}
background: Rectangle {
radius: Looks.radius.medium
color: root.color
}
}
@@ -10,42 +10,37 @@ import qs.modules.waffle.looks
PopupToolTip { PopupToolTip {
id: root id: root
property real padding: 2 property Item realContentItem
verticalPadding: padding realContentItem: WText {
horizontalPadding: padding text: root.text
anchors.centerIn: parent
}
property real visualMargin: 11
verticalPadding: visualMargin
horizontalPadding: visualMargin
property real realContentVerticalPadding: 8
property real realContentHorizontalPadding: 10
contentItem: Item { contentItem: Item {
anchors.centerIn: parent anchors.centerIn: parent
implicitWidth: realContent.implicitWidth + root.verticalPadding * 2 implicitWidth: realContent.implicitWidth + 2 * 2
implicitHeight: realContent.implicitHeight + root.horizontalPadding * 2 implicitHeight: realContent.implicitHeight + 2 * 2
Rectangle { WAmbientShadow {
id: ambientShadow target: realContent
z: 0
anchors {
fill: realContent
margins: -border.width
}
border.color: ColorUtils.transparentize(Looks.colors.bg0Border, Looks.shadowTransparency)
border.width: 1
color: "transparent"
radius: realContent.radius + border.width
} }
Rectangle { Rectangle {
id: realContent id: realContent
z: 1 z: 1
anchors.centerIn: parent anchors.centerIn: parent
implicitWidth: tooltipText.implicitWidth + 10 * 2 implicitWidth: root.realContentItem.implicitWidth + root.realContentHorizontalPadding * 2
implicitHeight: tooltipText.implicitHeight + 8 * 2 implicitHeight: root.realContentItem.implicitHeight + root.realContentVerticalPadding * 2
color: Looks.colors.bg1 color: Looks.colors.bg1
radius: Looks.radius.medium radius: Looks.radius.medium
WText { children: [root.realContentItem]
id: tooltipText
text: root.text
anchors.centerIn: parent
}
} }
} }
} }
@@ -135,10 +135,18 @@ Singleton {
} }
function syncBrightness() { function syncBrightness() {
const brightnessValue = Math.max(monitor.multipliedBrightness, 0) const brightnessValue = Math.max(monitor.multipliedBrightness, 0);
const rawValueRounded = Math.max(Math.floor(brightnessValue * monitor.rawMaxBrightness), 1); if (isDdc) {
setProc.command = isDdc ? ["ddcutil", "-b", busNum, "setvcp", "10", rawValueRounded] : ["brightnessctl", "--class", "backlight", "s", rawValueRounded, "--quiet"]; const rawValueRounded = Math.max(Math.floor(brightnessValue * monitor.rawMaxBrightness), 1);
setProc.startDetached(); setProc.command = ["ddcutil", "-b", busNum, "setvcp", "10", rawValueRounded];
setProc.startDetached();
} else {
const valuePercentNumber = Math.floor(brightnessValue * 100);
let valuePercent = `${valuePercentNumber}%`;
if (valuePercentNumber == 0) valuePercent = "1"; // Prevent fully black
setProc.command = ["brightnessctl", "--class", "backlight", "s", valuePercent, "--quiet"];
setProc.startDetached();
}
} }
function setBrightness(value: real): void { function setBrightness(value: real): void {
@@ -30,7 +30,7 @@ Singleton {
function enable() { function enable() {
root.active = true root.active = true
Quickshell.execDetached(["bash", "-c", "easyeffects --gapplication-service || flatpak run com.github.wwmm.easyeffects --gapplication-service"]) Quickshell.execDetached(["bash", "-c", "easyeffects --hide-window --service-mode || flatpak run com.github.wwmm.easyeffects --hide-window --service-mode"])
} }
function toggle() { function toggle() {
@@ -58,6 +58,7 @@ Singleton {
// Update the distroIcon property based on distroId // Update the distroIcon property based on distroId
switch (distroId) { switch (distroId) {
case "artix":
case "arch": distroIcon = "arch-symbolic"; break; case "arch": distroIcon = "arch-symbolic"; break;
case "endeavouros": distroIcon = "endeavouros-symbolic"; break; case "endeavouros": distroIcon = "endeavouros-symbolic"; break;
case "cachyos": distroIcon = "cachyos-symbolic"; break; case "cachyos": distroIcon = "cachyos-symbolic"; break;
@@ -8,6 +8,14 @@ import Quickshell.Wayland
Singleton { Singleton {
id: root id: root
function togglePin(appId) {
if (Config.options.dock.pinnedApps.indexOf(appId) !== -1) {
Config.options.dock.pinnedApps = Config.options.dock.pinnedApps.filter(id => id !== appId)
} else {
Config.options.dock.pinnedApps = Config.options.dock.pinnedApps.concat([appId])
}
}
property list<var> apps: { property list<var> apps: {
var map = new Map(); var map = new Map();
@@ -0,0 +1,45 @@
pragma Singleton
import qs.modules.common
import QtQuick
import Quickshell
import Quickshell.Services.SystemTray
Singleton {
id: root
property bool smartTray: Config.options.tray.filterPassive
property list<var> itemsInUserList: SystemTray.items.values.filter(i => (Config.options.tray.pinnedItems.includes(i.id) && (!smartTray || i.status !== Status.Passive)))
property list<var> itemsNotInUserList: SystemTray.items.values.filter(i => (!Config.options.tray.pinnedItems.includes(i.id) && (!smartTray || i.status !== Status.Passive)))
property bool invertPins: Config.options.tray.invertPinnedItems
property list<var> pinnedItems: invertPins ? itemsNotInUserList : itemsInUserList
property list<var> unpinnedItems: invertPins ? itemsInUserList : itemsNotInUserList
function getTooltipForItem(item) {
var result = item.tooltipTitle.length > 0 ? item.tooltipTitle
: (item.title.length > 0 ? item.title : item.id);
if (item.tooltipDescription.length > 0) result += " • " + item.tooltipDescription;
if (Config.options.tray.showItemId) result += "\n[" + item.id + "]";
return result;
}
// Pinning
function pin(itemId) {
var pins = Config.options.tray.pinnedItems;
if (pins.includes(itemId)) return;
Config.options.tray.pinnedItems.push(itemId);
}
function unpin(itemId) {
Config.options.tray.pinnedItems = Config.options.tray.pinnedItems.filter(id => id !== itemId);
}
function togglePin(itemId) {
var pins = Config.options.tray.pinnedItems;
if (pins.includes(itemId)) {
unpin(itemId)
} else {
pin(itemId)
}
}
}
@@ -0,0 +1,57 @@
pragma Singleton
import qs.modules.common
import qs.modules.common.functions
import QtQuick
import Quickshell
import Quickshell.Io
/*
* System updates service. Currently only supports Arch.
*/
Singleton {
id: root
property bool available: false
property int count: 0
readonly property bool updateAdvised: available && count > Config.options.updates.adviseUpdateThreshold
readonly property bool updateStronglyAdvised: available && count > Config.options.updates.stronglyAdviseUpdateThreshold
function load() {}
function refresh() {
if (!available) return;
print("[Updates] Checking for system updates")
checkUpdatesProc.running = true;
}
Timer {
interval: Config.options.updates.checkInterval * 60 * 1000
repeat: true
running: Config.ready
onTriggered: {
print("[Updates] Periodic update check due")
root.refresh();
}
}
Process {
id: checkAvailabilityProc
running: true
command: ["which", "checkupdates"]
onExited: (exitCode, exitStatus) => {
root.available = (exitCode === 0);
root.refresh();
}
}
Process {
id: checkUpdatesProc
command: ["bash", "-c", "checkupdates | wc -l"]
stdout: StdioCollector {
onStreamFinished: {
root.count = parseInt(text.trim());
}
}
}
}
+4 -1
View File
@@ -28,6 +28,7 @@ import qs.modules.ii.overlay
import qs.modules.ii.verticalBar import qs.modules.ii.verticalBar
import qs.modules.ii.wallpaperSelector import qs.modules.ii.wallpaperSelector
import qs.modules.waffle.actionCenter
import qs.modules.waffle.background import qs.modules.waffle.background
import qs.modules.waffle.bar import qs.modules.waffle.bar
@@ -49,6 +50,7 @@ ShellRoot {
ConflictKiller.load() ConflictKiller.load()
Cliphist.refresh() Cliphist.refresh()
Wallpapers.load() Wallpapers.load()
Updates.load()
} }
// Load enabled stuff // Load enabled stuff
@@ -74,6 +76,7 @@ ShellRoot {
PanelLoader { identifier: "iiSidebarRight"; component: SidebarRight {} } PanelLoader { identifier: "iiSidebarRight"; component: SidebarRight {} }
PanelLoader { identifier: "iiVerticalBar"; extraCondition: Config.options.bar.vertical; component: VerticalBar {} } PanelLoader { identifier: "iiVerticalBar"; extraCondition: Config.options.bar.vertical; component: VerticalBar {} }
PanelLoader { identifier: "iiWallpaperSelector"; component: WallpaperSelector {} } PanelLoader { identifier: "iiWallpaperSelector"; component: WallpaperSelector {} }
PanelLoader { identifier: "wActionCenter"; component: WaffleActionCenter {} }
PanelLoader { identifier: "wBar"; component: WaffleBar {} } PanelLoader { identifier: "wBar"; component: WaffleBar {} }
PanelLoader { identifier: "wBackground"; component: WaffleBackground {} } PanelLoader { identifier: "wBackground"; component: WaffleBackground {} }
@@ -87,7 +90,7 @@ ShellRoot {
property list<string> families: ["ii", "waffle"] property list<string> families: ["ii", "waffle"]
property var panelFamilies: ({ property var panelFamilies: ({
"ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiReloadPopup", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"], "ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiReloadPopup", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"],
"waffle": ["wBar", "wBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiReloadPopup", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiWallpaperSelector"], "waffle": ["wBar", "wBackground", "wActionCenter", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiReloadPopup", "iiSessionScreen", "iiSidebarRight", "iiWallpaperSelector"],
}) })
function cyclePanelFamily() { function cyclePanelFamily() {
const currentIndex = families.indexOf(Config.options.panelFamily) const currentIndex = families.indexOf(Config.options.panelFamily)
+1
View File
@@ -211,6 +211,7 @@ Extra dependencies.
- `qt6-translations` - `qt6-translations`
- `qt6-virtualkeyboard` - `qt6-virtualkeyboard`
- `qt6-wayland` - `qt6-wayland`
- `kirigami`
- `kdialog` - `kdialog`
- `syntax-highlighting` - `syntax-highlighting`
@@ -9,7 +9,7 @@ conflicts=("quickshell-git")
_pkgname=quickshell _pkgname=quickshell
pkgname="$_prefix-$_pkgname-git" pkgname="$_prefix-$_pkgname-git"
pkgver=0.1.0.r1 pkgver=0.1.0.r1
pkgrel=5 pkgrel=6
pkgdesc="$_pkgname-git pinned commit and extra deps for $_prefix" pkgdesc="$_pkgname-git pinned commit and extra deps for $_prefix"
arch=(x86_64 aarch64) arch=(x86_64 aarch64)
url='https://git.outfoxxed.me/quickshell/quickshell' url='https://git.outfoxxed.me/quickshell/quickshell'
@@ -39,6 +39,7 @@ depends=(
qt6-translations qt6-translations
qt6-virtualkeyboard qt6-virtualkeyboard
qt6-wayland qt6-wayland
kirigami
kdialog kdialog
syntax-highlighting syntax-highlighting
) )
@@ -1,36 +0,0 @@
Name: Bibata-Modern-Classic
Version: 2.0.7
Release: %autorelease
Summary: Open source, compact, and material designed cursor set.
License: GPL-3.0
URL: https://github.com/ful1e5/Bibata_Cursor
Source0: %{name}.tar.xz
BuildArch: noarch
%description
Open source, compact, and material designed cursor set.
%prep
wget --content-disposition -q -N -P %{_sourcedir} %{url}/releases/download/v%{version}/Bibata-Modern-Classic.tar.xz
wget -q -O %{_buildrootdir}/LICENSE %{url}/raw/refs/heads/main/LICENSE
%setup -q -n %{name}
%build
:
%install
install -d -m 0755 %{buildroot}%{_iconsdir}/Bibata-Modern-Classic
cp -r * %{buildroot}%{_iconsdir}/Bibata-Modern-Classic
install -d -m 0755 %{buildroot}%{_licensedir}/%{name}
install -m 0644 %{_buildrootdir}/LICENSE %{buildroot}%{_licensedir}/%{name}/
%files
%{_iconsdir}/Bibata-Modern-Classic
%license %{_licensedir}/%{name}/LICENSE
%changelog
%autochangelog
@@ -1,42 +0,0 @@
Name: JetBrainsMonoNerdFont-Regular
Version: 1.2
Release: %autorelease
Summary: JetBrainsMonoNerdFonts (TrueType Outlines) (Regulear)
License: MIT
URL: https://github.com/Zhaopudark/JetBrainsMonoNerdFonts
Source0: %{name}
BuildRequires: fonts-rpm-macros
BuildArch: noarch
%description
An auto-updated compiling version of JetBrains Mono that has been patched with Nerd Fonts.
%prep
wget --content-disposition -q -N -P %{_sourcedir} %{url}/releases/download/v%{version}/JetBrainsMonoNerdFont-Regular-v%{version}.ttf
wget -q -P %{_sourcedir} %{url}/raw/refs/heads/main/LICENSE
%build
:
%install
install -d -m 0755 %{buildroot}%{_fontdir}
install -m 0644 %{_sourcedir}/JetBrainsMonoNerdFont*ttf %{buildroot}%{_fontdir}
install -d -m 0755 %{buildroot}%{_licensedir}/%{name}
install -m 0644 %{_sourcedir}/LICENSE %{buildroot}%{_licensedir}/%{name}/
%post
/usr/bin/fc-cache -fv >/dev/null 2>&1 || :
%postun
/usr/bin/fc-cache -fv >/dev/null 2>&1 || :
%files
%{_fontdir}/JetBrainsMonoNerdFont*ttf
%license %{_licensedir}/%{name}/LICENSE
%changelog
%autochangelog
-50
View File
@@ -1,50 +0,0 @@
%global commit0 0e3707f6dafebb121d98b53c64364d16fefe481d
%global shortcommit0 %(c=%{commit0}; echo ${c:0:7})
%global bumpver 100
Name: MicroTeX
Version: 0.0.1%{?bumpver:^%{bumpver}.git%{shortcommit0}}
Release: %autorelease
Summary: A dynamic, cross-platform, and embeddable LaTeX rendering library
License: MIT
URL: https://github.com/NanoMichael/MicroTeX
Source0: %{name}-%{shortcommit0}.tar.gz
BuildRequires: gcc-c++ cmake
BuildRequires: pkgconfig(tinyxml2)
BuildRequires: gtkmm3.0-devel gtksourceviewmm3-devel cairomm-devel
%description
MicroTeX is a library for rendering LaTeX mathematical formulas, supporting multiple backends
such as GTK+, Qt, and Skia. It provides both library components and demo applications for
testing LaTeX rendering.
%prep
curl -fsSL --retry 3 \
https://codeload.github.com/NanoMichael/MicroTeX/tar.gz/%{shortcommit0} \
-o %{_sourcedir}/%{name}-%{shortcommit0}.tar.gz
%setup -q -n %{name}-%{shortcommit0}
%build
mkdir -p build
cd build
cmake ..
make -j$(nproc)
%install
mkdir -p %{buildroot}/opt/MicroTeX
cp build/LaTeX %{buildroot}/opt/MicroTeX/
cp -r build/res %{buildroot}/opt/MicroTeX/
install -Dpm 0644 LICENSE %{buildroot}%{_licensedir}/%{name}/LICENSE
install -Dpm 0644 res/greek/LICENSE %{buildroot}%{_licensedir}/%{name}/LICENSE-greek
install -Dpm 0644 res/cyrillic/LICENSE %{buildroot}%{_licensedir}/%{name}/LICENSE-cyrillic
%files
/opt/MicroTeX/
%license %{_licensedir}/%{name}/
%changelog
%autochangelog
-38
View File
@@ -1,38 +0,0 @@
Name: breeze-plus
Version: 6.19.0
Release: %autorelease
Summary: Breeze theme with additional icons
License: LGPL-2.1
URL: https://github.com/mjkim0727/breeze-plus
Source0: %{name}-%{version}.tar.gz
BuildArch: noarch
%description
Breeze icon theme with additional icons for applications not covered by the
official Breeze theme. Includes icons for Wine, third-party apps, and more.
%prep
wget --content-disposition -q -N -P %{_sourcedir} %{url}/archive/refs/tags/%{version}.tar.gz
%setup -q
%build
:
%install
install -d -m 0755 %{buildroot}%{_iconsdir}/breeze-plus
cp -r src/breeze-plus %{buildroot}%{_iconsdir}/
cp -r src/breeze-plus-dark %{buildroot}%{_iconsdir}/
install -d -m 0755 %{buildroot}%{_licensedir}/%{name}
install -m 0644 LICENSE %{buildroot}%{_licensedir}/%{name}/
%files
%{_iconsdir}/breeze-plus/
%{_iconsdir}/breeze-plus-dark/
%license %{_licensedir}/%{name}/LICENSE
%changelog
%autochangelog

Some files were not shown because too many files have changed in this diff Show More