Merge branch 'main' into main
@@ -1,2 +1,10 @@
|
||||
# You can put extra environment variables here
|
||||
# https://wiki.hyprland.org/Configuring/Environment-variables/
|
||||
|
||||
# ######### Input method ##########
|
||||
# See https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland
|
||||
#env = QT_IM_MODULE, fcitx
|
||||
#env = XMODIFIERS, @im=fcitx
|
||||
#env = SDL_IM_MODULE, fcitx
|
||||
#env = GLFW_IM_MODULE, ibus
|
||||
#env = INPUT_METHOD, fcitx
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
# You can make apps auto-start here
|
||||
# Relevant Hyprland wiki section: https://wiki.hyprland.org/Configuring/Keywords/#executing
|
||||
|
||||
# Input method
|
||||
# exec-once = fcitx5
|
||||
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
# ######### Input method ##########
|
||||
# See https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland
|
||||
#env = QT_IM_MODULE, fcitx
|
||||
#env = XMODIFIERS, @im=fcitx
|
||||
#env = SDL_IM_MODULE, fcitx
|
||||
#env = GLFW_IM_MODULE, ibus
|
||||
#env = INPUT_METHOD, fcitx
|
||||
|
||||
# ############ Wayland #############
|
||||
env = ELECTRON_OZONE_PLATFORM_HINT,auto
|
||||
|
||||
|
||||
@@ -3,9 +3,6 @@ exec-once = ~/.config/hypr/hyprland/scripts/start_geoclue_agent.sh
|
||||
exec-once = qs -c $qsConfig &
|
||||
exec-once = ~/.config/hypr/custom/scripts/__restore_video_wallpaper.sh
|
||||
|
||||
# Input method
|
||||
# exec-once = fcitx5
|
||||
|
||||
# Core components (authentication, lock screen, notification daemon)
|
||||
exec-once = gnome-keyring-daemon --start --components=secrets
|
||||
exec-once = hypridle
|
||||
|
||||
@@ -4,27 +4,27 @@
|
||||
#!
|
||||
##! Shell
|
||||
# These absolutely need to be on top, or they won't work consistently
|
||||
bindid = Super, Super_L, Toggle overview, global, quickshell:overviewToggleRelease # Toggle overview/launcher
|
||||
bindid = Super, Super_R, Toggle overview, global, quickshell:overviewToggleRelease # [hidden] Toggle overview/launcher
|
||||
bindid = Super, Super_L, Toggle search, global, quickshell:searchToggleRelease # Toggle search
|
||||
bindid = Super, Super_R, Toggle search, global, quickshell:searchToggleRelease # [hidden] Toggle search
|
||||
bind = Super, Super_L, exec, qs -c $qsConfig ipc call TEST_ALIVE || pkill fuzzel || fuzzel # [hidden] Launcher (fallback)
|
||||
bind = Super, Super_R, exec, qs -c $qsConfig ipc call TEST_ALIVE || pkill fuzzel || fuzzel # [hidden] Launcher (fallback)
|
||||
binditn = Super, catchall, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
|
||||
bind = Ctrl, Super_L, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
|
||||
bind = Ctrl, Super_R, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse:272, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse:273, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse:274, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse:275, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse:276, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse:277, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse_up, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse_down,global, quickshell:overviewToggleReleaseInterrupt # [hidden]
|
||||
binditn = Super, catchall, global, quickshell:searchToggleReleaseInterrupt # [hidden]
|
||||
bind = Ctrl, Super_L, global, quickshell:searchToggleReleaseInterrupt # [hidden]
|
||||
bind = Ctrl, Super_R, global, quickshell:searchToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse:272, global, quickshell:searchToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse:273, global, quickshell:searchToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse:274, global, quickshell:searchToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse:275, global, quickshell:searchToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse:276, global, quickshell:searchToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse:277, global, quickshell:searchToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse_up, global, quickshell:searchToggleReleaseInterrupt # [hidden]
|
||||
bind = Super, mouse_down,global, quickshell:searchToggleReleaseInterrupt # [hidden]
|
||||
|
||||
bindit = ,Super_L, global, quickshell:workspaceNumber # [hidden]
|
||||
bindit = ,Super_R, global, quickshell:workspaceNumber # [hidden]
|
||||
bind = Super, Tab, global, quickshell:overviewWorkspacesToggle # Toggle overview
|
||||
bindd = Super, V, Clipboard history >> clipboard, global, quickshell:overviewClipboardToggle # Clipboard history >> clipboard
|
||||
bindd = Super, Period, Emoji >> clipboard, global, quickshell:overviewEmojiToggle # Emoji >> clipboard
|
||||
bind = Super, Tab, global, quickshell:overviewWorkspacesToggle # [hidden] Toggle overview/launcher (alt)
|
||||
bind = Super, A, global, quickshell:sidebarLeftToggle # Toggle left sidebar
|
||||
bind = Super+Alt, A, global, quickshell:sidebarLeftToggleDetach # [hidden]
|
||||
bind = Super, B, global, quickshell:sidebarLeftToggle # [hidden]
|
||||
@@ -218,8 +218,8 @@ submap = global
|
||||
|
||||
#!
|
||||
# Testing
|
||||
bind = Super+Alt, f11, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification with body image" "This notification should contain your user account <b>image</b> and <a href=\"https://discord.com/app\">Discord</a> <b>icon</b>. Oh and here is a random image in your Pictures folder: <img src=\"$RANDOM_IMAGE\" alt=\"Testing image\"/>" -a "Hyprland keybind" -p -h "string:image-path:/var/lib/AccountsService/icons/$USER" -t 6000 -i "discord" -A "openImage=Open profile image" -A "action2=Open the random image" -A "action3=Useless button"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"; [[ $ACTION == *action2 ]] && xdg-open \"$RANDOM_IMAGE\"' # [hidden]
|
||||
bind = Super+Alt, f12, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification" "This notification should contain a random image in your <b>Pictures</b> folder and <a href=\"https://discord.com/app\">Discord</a> <b>icon</b>.\n<i>Flick right to dismiss!</i>" -a "Discord (fake)" -p -h "string:image-path:$RANDOM_IMAGE" -t 6000 -i "discord" -A "openImage=Open profile image" -A "action2=Useless button" -A "action3=Cry more"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"' # [hidden]
|
||||
bind = Super+Alt, f11, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification with body image" "This notification should contain your user account <b>image</b> and <a href=\"https://discord.com/app\">Discord</a> <b>icon</b>. Oh and here is a random image in your Pictures folder: <img src=\"$RANDOM_IMAGE\" alt=\"Testing image\"/>" -a "Hyprland keybind" -p -h "string:image-path:/var/lib/AccountsService/icons/$USER" -t 6000 -i "discord" -A "openImage=Profile image" -A "action2=Open the random image" -A "action3=Useless button"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"; [[ $ACTION == *action2 ]] && xdg-open \"$RANDOM_IMAGE\"' # [hidden]
|
||||
bind = Super+Alt, f12, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification" "This notification should contain a random image in your <b>Pictures</b> folder and <a href=\"https://discord.com/app\">Discord</a> <b>icon</b>.\n<i>Flick right to dismiss!</i>" -a "Discord (fake)" -p -h "string:image-path:$RANDOM_IMAGE" -t 6000 -i "discord" -A "openImage=Profile image" -A "action2=Useless button"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"' # [hidden]
|
||||
bind = Super+Alt, Equal, exec, notify-send "Urgent notification" "Ah hell no" -u critical -a 'Hyprland keybind' # [hidden]
|
||||
|
||||
##! Session
|
||||
|
||||
@@ -159,7 +159,9 @@ layerrule = animation slide right, quickshell:sidebarRight
|
||||
layerrule = animation slide left, quickshell:sidebarLeft
|
||||
layerrule = animation slide, quickshell:verticalBar
|
||||
layerrule = animation slide top, quickshell:wallpaperSelector
|
||||
layerrule = noanim, quickshell:wNotificationCenter
|
||||
layerrule = noanim, quickshell:wOnScreenDisplay
|
||||
layerrule = noanim, quickshell:wStartMenu
|
||||
|
||||
# Launchers need to be FAST
|
||||
layerrule = noanim, gtk4-layer-shell
|
||||
|
||||
@@ -20,6 +20,7 @@ Singleton {
|
||||
property bool overlayOpen: false
|
||||
property bool overviewOpen: false
|
||||
property bool regionSelectorOpen: false
|
||||
property bool searchOpen: false
|
||||
property bool screenLocked: false
|
||||
property bool screenLockContainsCharacters: false
|
||||
property bool screenUnlockFailed: false
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_525_6" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="4" y="4" width="56" height="56">
|
||||
<rect x="4.5" y="4.5" width="26.5" height="26.5" fill="#D9D9D9"/>
|
||||
<rect x="4.5" y="33" width="26.5" height="26.5" fill="#D9D9D9"/>
|
||||
<rect x="33" y="4.5" width="26.5" height="26.5" fill="#D9D9D9"/>
|
||||
<rect x="33" y="33" width="26.5" height="26.5" fill="#D9D9D9"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_525_6)">
|
||||
<rect width="64" height="64" fill="url(#paint0_linear_525_6)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_525_6" x1="0" y1="0" x2="63.6279" y2="64" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#5AE8C0"/>
|
||||
<stop offset="0.99563" stop-color="#119979"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 795 B |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#000000">
|
||||
<path d="M8.20514 4.84312C8.70586 4.61008 9.30068 4.82707 9.53372 5.32778C9.76676 5.82849 9.54977 6.42331 9.04906 6.65635C6.59946 7.79644 5 10.2547 5 13.003C5 16.8671 8.13391 19.9997 12 19.9997C15.8661 19.9997 19 16.8671 19 13.003C19 10.2604 17.4072 7.80631 14.9653 6.66304C14.4651 6.42887 14.2495 5.83355 14.4836 5.33337C14.7178 4.83319 15.3131 4.61756 15.8133 4.85173C18.9517 6.32109 21 9.47689 21 13.003C21 17.9719 16.9705 21.9997 12 21.9997C7.02953 21.9997 3 17.9719 3 13.003C3 9.46957 5.05682 6.30841 8.20514 4.84312ZM12 1.99902C12.5128 1.99902 12.9355 2.38506 12.9933 2.8824L13 2.99902V10.0004C13 10.5527 12.5523 11.0004 12 11.0004C11.4872 11.0004 11.0645 10.6144 11.0067 10.1171L11 10.0004V2.99902C11 2.44674 11.4477 1.99902 12 1.99902Z" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 906 B |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#000000">
|
||||
<path d="M8.2042 4.82046C8.57962 4.64545 9.02584 4.80792 9.20085 5.18334C9.37586 5.55876 9.2134 6.00498 8.83797 6.18C6.21382 7.4033 4.5 10.0416 4.5 12.9914C4.5 17.1386 7.85759 20.5002 11.9989 20.5002C16.1403 20.5002 19.4979 17.1386 19.4979 12.9914C19.4979 10.0477 17.7912 7.41389 15.1753 6.18718C14.8002 6.01131 14.6388 5.56472 14.8147 5.1897C14.9905 4.81467 15.4371 4.65322 15.8121 4.82909C18.9502 6.30065 20.9979 9.46066 20.9979 12.9914C20.9979 17.9666 16.9691 22.0002 11.9989 22.0002C7.02876 22.0002 3 17.9666 3 12.9914C3 9.45334 5.05623 6.28796 8.2042 4.82046ZM11.9989 2.49609C12.3786 2.49609 12.6924 2.77825 12.7421 3.14432L12.7489 3.24609V10.746C12.7489 11.1602 12.4132 11.496 11.9989 11.496C11.6192 11.496 11.3055 11.2139 11.2558 10.8478L11.2489 10.746V3.24609C11.2489 2.83188 11.5847 2.49609 11.9989 2.49609Z" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 979 B |
@@ -1,24 +1,120 @@
|
||||
<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>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="64"
|
||||
height="64"
|
||||
viewBox="0 0 64 64"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg11"
|
||||
sodipodi:docname="start-here-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="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview11"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="6.375"
|
||||
inkscape:cx="32.156863"
|
||||
inkscape:cy="28.862745"
|
||||
inkscape:window-width="1164"
|
||||
inkscape:window-height="1020"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg11" />
|
||||
<g
|
||||
id="g11"
|
||||
transform="translate(0.5,0.5)">
|
||||
<path
|
||||
d="M 4,6.2 C 4,4.98497 4.98497,4 6.2,4 h 22 c 1.215,0 2.2,0.98497 2.2,2.2 v 22 c 0,1.215 -0.985,2.2 -2.2,2.2 H 6.2 C 4.98497,30.4 4,29.415 4,28.2 Z"
|
||||
fill="url(#paint0_radial_520_19)"
|
||||
id="path1"
|
||||
style="fill:url(#paint0_radial_520_19)" />
|
||||
<path
|
||||
d="M 32.6,6.2 C 32.6,4.98497 33.585,4 34.8,4 h 22 C 58.015,4 59,4.98497 59,6.2 v 22 c 0,1.215 -0.985,2.2 -2.2,2.2 h -22 c -1.215,0 -2.2,-0.985 -2.2,-2.2 z"
|
||||
fill="url(#paint1_radial_520_19)"
|
||||
id="path2"
|
||||
style="fill:url(#paint1_radial_520_19)" />
|
||||
<path
|
||||
d="m 32.6,34.8 c 0,-1.215 0.985,-2.2 2.2,-2.2 h 22 c 1.215,0 2.2,0.985 2.2,2.2 v 22 c 0,1.215 -0.985,2.2 -2.2,2.2 h -22 c -1.215,0 -2.2,-0.985 -2.2,-2.2 z"
|
||||
fill="url(#paint2_radial_520_19)"
|
||||
id="path3"
|
||||
style="fill:url(#paint2_radial_520_19)" />
|
||||
<path
|
||||
d="m 4,34.8 c 0,-1.215 0.98497,-2.2 2.2,-2.2 h 22 c 1.215,0 2.2,0.985 2.2,2.2 v 22 c 0,1.215 -0.985,2.2 -2.2,2.2 H 6.2 C 4.98497,59 4,58.015 4,56.8 Z"
|
||||
fill="url(#paint3_radial_520_19)"
|
||||
id="path4"
|
||||
style="fill:url(#paint3_radial_520_19)" />
|
||||
</g>
|
||||
<defs
|
||||
id="defs11">
|
||||
<radialGradient
|
||||
id="paint0_radial_520_19"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(54.999968,54.999968,-54.999968,54.999968,4,4)">
|
||||
<stop
|
||||
stop-color="#0B9BFE"
|
||||
id="stop4" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#0B9BFE"
|
||||
id="stop5" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="paint1_radial_520_19"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(54.999968,54.999968,-54.999968,54.999968,4,4)">
|
||||
<stop
|
||||
stop-color="#0B9BFE"
|
||||
id="stop6" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#0B9BFE"
|
||||
id="stop7" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="paint2_radial_520_19"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(54.999968,54.999968,-54.999968,54.999968,4,4)">
|
||||
<stop
|
||||
stop-color="#0B9BFE"
|
||||
id="stop8" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#0B9BFE"
|
||||
id="stop9" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="paint3_radial_520_19"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(54.999968,54.999968,-54.999968,54.999968,4,4)">
|
||||
<stop
|
||||
stop-color="#0B9BFE"
|
||||
id="stop10" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#0B9BFE"
|
||||
id="stop11" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 3.7 KiB |
@@ -1,24 +1,120 @@
|
||||
<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>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="64"
|
||||
height="64"
|
||||
viewBox="0 0 64 64"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg11"
|
||||
sodipodi:docname="start-here.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="namedview11"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="4.5078057"
|
||||
inkscape:cx="53.3519"
|
||||
inkscape:cy="28.838865"
|
||||
inkscape:window-width="1113"
|
||||
inkscape:window-height="1020"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg11" />
|
||||
<g
|
||||
id="g11"
|
||||
transform="translate(0.5,0.5)">
|
||||
<path
|
||||
d="M 4,6.2 C 4,4.98497 4.98497,4 6.2,4 h 22 c 1.215,0 2.2,0.98497 2.2,2.2 v 22 c 0,1.215 -0.985,2.2 -2.2,2.2 H 6.2 C 4.98497,30.4 4,29.415 4,28.2 Z"
|
||||
fill="url(#paint0_radial_519_6)"
|
||||
id="path1"
|
||||
style="fill:url(#paint0_radial_519_6)" />
|
||||
<path
|
||||
d="M 32.6,6.2 C 32.6,4.98497 33.585,4 34.8,4 h 22 C 58.015,4 59,4.98497 59,6.2 v 22 c 0,1.215 -0.985,2.2 -2.2,2.2 h -22 c -1.215,0 -2.2,-0.985 -2.2,-2.2 z"
|
||||
fill="url(#paint1_radial_519_6)"
|
||||
id="path2"
|
||||
style="fill:url(#paint1_radial_519_6)" />
|
||||
<path
|
||||
d="m 32.6,34.8 c 0,-1.215 0.985,-2.2 2.2,-2.2 h 22 c 1.215,0 2.2,0.985 2.2,2.2 v 22 c 0,1.215 -0.985,2.2 -2.2,2.2 h -22 c -1.215,0 -2.2,-0.985 -2.2,-2.2 z"
|
||||
fill="url(#paint2_radial_519_6)"
|
||||
id="path3"
|
||||
style="fill:url(#paint2_radial_519_6)" />
|
||||
<path
|
||||
d="m 4,34.8 c 0,-1.215 0.98497,-2.2 2.2,-2.2 h 22 c 1.215,0 2.2,0.985 2.2,2.2 v 22 c 0,1.215 -0.985,2.2 -2.2,2.2 H 6.2 C 4.98497,59 4,58.015 4,56.8 Z"
|
||||
fill="url(#paint3_radial_519_6)"
|
||||
id="path4"
|
||||
style="fill:url(#paint3_radial_519_6)" />
|
||||
</g>
|
||||
<defs
|
||||
id="defs11">
|
||||
<radialGradient
|
||||
id="paint0_radial_519_6"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(54.999968,54.999968,-54.999968,54.999968,4,4)">
|
||||
<stop
|
||||
stop-color="#81DFFF"
|
||||
id="stop4" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#0A99F9"
|
||||
id="stop5" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="paint1_radial_519_6"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(54.999968,54.999968,-54.999968,54.999968,4,4)">
|
||||
<stop
|
||||
stop-color="#81DFFF"
|
||||
id="stop6" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#0A99F9"
|
||||
id="stop7" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="paint2_radial_519_6"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(54.999968,54.999968,-54.999968,54.999968,4,4)">
|
||||
<stop
|
||||
stop-color="#81DFFF"
|
||||
id="stop8" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#0A99F9"
|
||||
id="stop9" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="paint3_radial_519_6"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(54.999968,54.999968,-54.999968,54.999968,4,4)">
|
||||
<stop
|
||||
stop-color="#81DFFF"
|
||||
id="stop10" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#0A99F9"
|
||||
id="stop11" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 3.7 KiB |
@@ -26,8 +26,8 @@
|
||||
inkscape:zoom="4.65625"
|
||||
inkscape:cx="32"
|
||||
inkscape:cy="32"
|
||||
inkscape:window-width="1197"
|
||||
inkscape:window-height="1020"
|
||||
inkscape:window-width="1595"
|
||||
inkscape:window-height="664"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
@@ -48,10 +48,10 @@
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient919"
|
||||
x1="4.3106"
|
||||
x2="14.36"
|
||||
y1="8.4665"
|
||||
y2="8.4665"
|
||||
x1="4.4818125"
|
||||
x2="14.188787"
|
||||
y1="7.1660123"
|
||||
y2="9.7669888"
|
||||
gradientTransform="matrix(1.226575,0,0,1.226575,-0.82407803,-6.4497629)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
@@ -61,7 +61,7 @@
|
||||
style="stop-color:#5fe277;stop-opacity:1;" />
|
||||
<stop
|
||||
stop-color="#55b4ff"
|
||||
offset="1"
|
||||
offset="0.40375727"
|
||||
id="stop2"
|
||||
style="stop-color:#0078d3;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
@@ -23,10 +23,10 @@
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="6.5849319"
|
||||
inkscape:cx="26.95548"
|
||||
inkscape:cx="27.031411"
|
||||
inkscape:cy="26.423963"
|
||||
inkscape:window-width="1257"
|
||||
inkscape:window-height="1020"
|
||||
inkscape:window-width="1621"
|
||||
inkscape:window-height="820"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
@@ -35,10 +35,10 @@
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="linearGradient919"
|
||||
x1="4.3106"
|
||||
x2="14.36"
|
||||
y1="8.4665"
|
||||
y2="8.4665"
|
||||
x1="4.4818139"
|
||||
x2="14.188786"
|
||||
y1="7.1660118"
|
||||
y2="9.7669868"
|
||||
gradientTransform="matrix(1.226575,0,0,1.226575,-0.82407803,-6.4497629)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
@@ -48,7 +48,7 @@
|
||||
style="stop-color:#5fe277;stop-opacity:1;" />
|
||||
<stop
|
||||
stop-color="#55b4ff"
|
||||
offset="1"
|
||||
offset="0.40380999"
|
||||
id="stop2"
|
||||
style="stop-color:#0078d3;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
@@ -154,6 +154,7 @@ Singleton {
|
||||
property JsonObject apps: JsonObject {
|
||||
property string bluetooth: "kcmshell6 kcm_bluetooth"
|
||||
property string network: "kcmshell6 kcm_networkmanagement"
|
||||
property string manageUser: "kcmshell6 kcm_users"
|
||||
property string networkEthernet: "kcmshell6 kcm_networkmanagement"
|
||||
property string taskManager: "plasma-systemmonitor --page-name Processes"
|
||||
property string terminal: "kitty -1" // This is only for shell actions
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.services
|
||||
import qs.modules.common.functions
|
||||
import QtCore
|
||||
import QtQuick
|
||||
@@ -46,6 +47,9 @@ Singleton {
|
||||
property string aiChats: FileUtils.trimFileProtocol(`${Directories.state}/user/ai/chats`)
|
||||
property string aiTranslationScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/ai/gemini-translate.sh`)
|
||||
property string recordScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/videos/record.sh`)
|
||||
property string userAvatarPathAccountsService: FileUtils.trimFileProtocol(`/var/lib/AccountsService/icons/${SystemInfo.username}`)
|
||||
property string userAvatarPathRicersAndWeirdSystems: FileUtils.trimFileProtocol(`${Directories.home}.face`)
|
||||
property string userAvatarPathRicersAndWeirdSystems2: FileUtils.trimFileProtocol(`${Directories.home}.face.icon`)
|
||||
// Cleanup on init
|
||||
Component.onCompleted: {
|
||||
Quickshell.execDetached(["mkdir", "-p", `${shellConfig}`])
|
||||
|
||||
@@ -84,4 +84,28 @@ Singleton {
|
||||
// Older dates
|
||||
return Qt.formatDateTime(messageTime, "MMMM dd");
|
||||
}
|
||||
|
||||
function processNotificationBody(body, appName) {
|
||||
let processedBody = body
|
||||
|
||||
// Clean Chromium-based browsers notifications - remove first line
|
||||
if (appName) {
|
||||
const lowerApp = appName.toLowerCase()
|
||||
const chromiumBrowsers = [
|
||||
"brave", "chrome", "chromium", "vivaldi", "opera", "microsoft edge"
|
||||
]
|
||||
|
||||
if (chromiumBrowsers.some(name => lowerApp.includes(name))) {
|
||||
const lines = body.split('\n\n')
|
||||
|
||||
if (lines.length > 1 && lines[0].startsWith('<a')) {
|
||||
processedBody = lines.slice(1).join('\n\n')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processedBody = processedBody.replace(/<img/gi, '\n\n<img');
|
||||
|
||||
return processedBody
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,14 +18,19 @@ Process {
|
||||
|
||||
running: true
|
||||
command: ["bash", "-c",
|
||||
`mkdir -p $(dirname '${processFilePath(filePath)}'); [ -f '${processFilePath(filePath)}' ] || curl -sSL '${sourceUrl}' -o '${processFilePath(filePath)}' && magick identify -format '%w %h' '${processFilePath(filePath)}'[0]`
|
||||
`mkdir -p $(dirname '${processFilePath()}'); [ -f '${processFilePath()}' ] || curl -sSL '${sourceUrl}' -o '${processFilePath()}' && file '${processFilePath()}'`
|
||||
]
|
||||
stdout: StdioCollector {
|
||||
id: imageSizeOutputCollector
|
||||
onStreamFinished: {
|
||||
const output = imageSizeOutputCollector.text.trim();
|
||||
const [width, height] = output.split(" ").map(Number);
|
||||
root.done(root.filePath, width, height);
|
||||
const match = output.match(/(\d+)\s*x\s*(\d+)/);
|
||||
|
||||
if (match) {
|
||||
const width = Number(match[1]);
|
||||
const height = Number(match[2]);
|
||||
root.done(root.filePath, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,28 +31,6 @@ Item { // Notification item area
|
||||
|
||||
implicitHeight: background.implicitHeight
|
||||
|
||||
function processNotificationBody(body, appName) {
|
||||
let processedBody = body
|
||||
|
||||
// Clean Chromium-based browsers notifications - remove first line
|
||||
if (appName) {
|
||||
const lowerApp = appName.toLowerCase()
|
||||
const chromiumBrowsers = [
|
||||
"brave", "chrome", "chromium", "vivaldi", "opera", "microsoft edge"
|
||||
]
|
||||
|
||||
if (chromiumBrowsers.some(name => lowerApp.includes(name))) {
|
||||
const lines = body.split('\n\n')
|
||||
|
||||
if (lines.length > 1 && lines[0].startsWith('<a')) {
|
||||
processedBody = lines.slice(1).join('\n\n')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return processedBody
|
||||
}
|
||||
|
||||
function destroyWithAnimation(left = false) {
|
||||
root.qmlParent.resetDrag()
|
||||
background.anchors.leftMargin = background.anchors.leftMargin; // Break binding
|
||||
@@ -196,12 +174,13 @@ Item { // Notification item area
|
||||
maximumLineCount: 1
|
||||
textFormat: Text.StyledText
|
||||
text: {
|
||||
return processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")
|
||||
return NotificationUtils.processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout { // Expanded content
|
||||
id: expandedContentColumn
|
||||
Layout.fillWidth: true
|
||||
opacity: root.expanded ? 1 : 0
|
||||
visible: opacity > 0
|
||||
@@ -218,8 +197,8 @@ Item { // Notification item area
|
||||
elide: Text.ElideRight
|
||||
textFormat: Text.RichText
|
||||
text: {
|
||||
return `<style>img{max-width:${300 /* binding to notificationBodyText.width would cause a binding loop */}px;}</style>` +
|
||||
`${processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")}`
|
||||
return `<style>img{max-width:${expandedContentColumn.width}px;}</style>` +
|
||||
`${NotificationUtils.processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")}`
|
||||
}
|
||||
|
||||
onLinkActivated: (link) => {
|
||||
@@ -293,6 +272,8 @@ Item { // Notification item area
|
||||
id: actionRepeater
|
||||
model: notificationObject.actions
|
||||
NotificationActionButton {
|
||||
id: notifAction
|
||||
required property var modelData
|
||||
Layout.fillWidth: true
|
||||
buttonText: modelData.text
|
||||
urgency: notificationObject.urgency
|
||||
|
||||
@@ -12,4 +12,14 @@ Image {
|
||||
Behavior on opacity {
|
||||
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
|
||||
}
|
||||
|
||||
property list<string> fallbacks: []
|
||||
property int currentFallbackIndex: 0
|
||||
|
||||
onStatusChanged: {
|
||||
if (status === Image.Error && currentFallbackIndex < fallbacks.length) {
|
||||
source = fallbacks[currentFallbackIndex];
|
||||
currentFallbackIndex += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ ToolTip {
|
||||
hintingPreference: Font.PreferNoHinting // Prevent shaky text
|
||||
}
|
||||
|
||||
delay: 0
|
||||
visible: internalVisibleCondition
|
||||
|
||||
contentItem: StyledToolTipContent {
|
||||
|
||||
@@ -162,7 +162,7 @@ Scope {
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "overview"
|
||||
target: "search"
|
||||
|
||||
function toggle() {
|
||||
GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
|
||||
@@ -185,8 +185,8 @@ Scope {
|
||||
}
|
||||
|
||||
GlobalShortcut {
|
||||
name: "overviewToggle"
|
||||
description: "Toggles overview on press"
|
||||
name: "searchToggle"
|
||||
description: "Toggles search on press"
|
||||
|
||||
onPressed: {
|
||||
GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
|
||||
@@ -201,16 +201,8 @@ Scope {
|
||||
}
|
||||
}
|
||||
GlobalShortcut {
|
||||
name: "overviewClose"
|
||||
description: "Closes overview"
|
||||
|
||||
onPressed: {
|
||||
GlobalStates.overviewOpen = false;
|
||||
}
|
||||
}
|
||||
GlobalShortcut {
|
||||
name: "overviewToggleRelease"
|
||||
description: "Toggles overview on release"
|
||||
name: "searchToggleRelease"
|
||||
description: "Toggles search on release"
|
||||
|
||||
onPressed: {
|
||||
GlobalStates.superReleaseMightTrigger = true;
|
||||
@@ -225,8 +217,8 @@ Scope {
|
||||
}
|
||||
}
|
||||
GlobalShortcut {
|
||||
name: "overviewToggleReleaseInterrupt"
|
||||
description: "Interrupts possibility of overview being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything."
|
||||
name: "searchToggleReleaseInterrupt"
|
||||
description: "Interrupts possibility of search being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything."
|
||||
|
||||
onPressed: {
|
||||
GlobalStates.superReleaseMightTrigger = false;
|
||||
|
||||
@@ -81,7 +81,7 @@ RowLayout {
|
||||
}
|
||||
}
|
||||
|
||||
onTextChanged: root.searchingText = text
|
||||
onTextChanged: LauncherSearch.query = text
|
||||
|
||||
onAccepted: {
|
||||
if (appResults.count > 0) {
|
||||
|
||||
@@ -14,81 +14,11 @@ import Quickshell.Io
|
||||
Item { // Wrapper
|
||||
id: root
|
||||
readonly property string xdgConfigHome: Directories.config
|
||||
property string searchingText: ""
|
||||
property string searchingText: LauncherSearch.query
|
||||
property bool showResults: searchingText != ""
|
||||
implicitWidth: searchWidgetContent.implicitWidth + Appearance.sizes.elevationMargin * 2
|
||||
implicitHeight: searchBar.implicitHeight + searchBar.verticalPadding * 2 + Appearance.sizes.elevationMargin * 2
|
||||
|
||||
property string mathResult: ""
|
||||
property bool clipboardWorkSafetyActive: {
|
||||
const enabled = Config.options.workSafety.enable.clipboard;
|
||||
const sensitiveNetwork = (StringUtils.stringListContainsSubstring(Network.networkName.toLowerCase(), Config.options.workSafety.triggerCondition.networkNameKeywords))
|
||||
return enabled && sensitiveNetwork;
|
||||
}
|
||||
|
||||
property var searchActions: [
|
||||
{
|
||||
action: "accentcolor",
|
||||
execute: args => {
|
||||
Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--noswitch", "--color", ...(args != '' ? [`${args}`] : [])]);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "dark",
|
||||
execute: () => {
|
||||
Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "dark", "--noswitch"]);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "konachanwallpaper",
|
||||
execute: () => {
|
||||
Quickshell.execDetached([Quickshell.shellPath("scripts/colors/random/random_konachan_wall.sh")]);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "light",
|
||||
execute: () => {
|
||||
Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "light", "--noswitch"]);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "superpaste",
|
||||
execute: args => {
|
||||
if (!/^(\d+)/.test(args.trim())) { // Invalid if doesn't start with numbers
|
||||
Quickshell.execDetached([
|
||||
"notify-send",
|
||||
Translation.tr("Superpaste"),
|
||||
Translation.tr("Usage: <tt>%1superpaste NUM_OF_ENTRIES[i]</tt>\nSupply <tt>i</tt> when you want images\nExamples:\n<tt>%1superpaste 4i</tt> for the last 4 images\n<tt>%1superpaste 7</tt> for the last 7 entries").arg(Config.options.search.prefix.action),
|
||||
"-a", "Shell"
|
||||
]);
|
||||
return;
|
||||
}
|
||||
const syntaxMatch = /^(?:(\d+)(i)?)/.exec(args.trim());
|
||||
const count = syntaxMatch[1] ? parseInt(syntaxMatch[1]) : 1;
|
||||
const isImage = !!syntaxMatch[2];
|
||||
Cliphist.superpaste(count, isImage);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "todo",
|
||||
execute: args => {
|
||||
Todo.addTask(args);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "wallpaper",
|
||||
execute: () => {
|
||||
GlobalStates.wallpaperSelectorOpen = true;
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "wipeclipboard",
|
||||
execute: () => {
|
||||
Cliphist.wipe();
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
function focusFirstItem() {
|
||||
appResults.currentIndex = 0;
|
||||
}
|
||||
@@ -103,13 +33,13 @@ Item { // Wrapper
|
||||
|
||||
function cancelSearch() {
|
||||
searchBar.searchInput.selectAll();
|
||||
root.searchingText = "";
|
||||
LauncherSearch.query = "";
|
||||
searchBar.animateWidth = true;
|
||||
}
|
||||
|
||||
function setSearchingText(text) {
|
||||
searchBar.searchInput.text = text;
|
||||
root.searchingText = text;
|
||||
LauncherSearch.query = text;
|
||||
}
|
||||
|
||||
function containsUnsafeLink(entry) {
|
||||
@@ -118,34 +48,6 @@ Item { // Wrapper
|
||||
return StringUtils.stringListContainsSubstring(entry.toLowerCase(), unsafeKeywords);
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: nonAppResultsTimer
|
||||
interval: Config.options.search.nonAppResultDelay
|
||||
onTriggered: {
|
||||
let expr = root.searchingText;
|
||||
if (expr.startsWith(Config.options.search.prefix.math)) {
|
||||
expr = expr.slice(Config.options.search.prefix.math.length);
|
||||
}
|
||||
mathProcess.calculateExpression(expr);
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: mathProcess
|
||||
property list<string> baseCommand: ["qalc", "-t"]
|
||||
function calculateExpression(expression) {
|
||||
mathProcess.running = false;
|
||||
mathProcess.command = baseCommand.concat(expression);
|
||||
mathProcess.running = true;
|
||||
}
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
root.mathResult = data;
|
||||
root.focusFirstItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: event => {
|
||||
// Prevent Esc and Backspace from registering
|
||||
if (event.key === Qt.Key_Escape)
|
||||
@@ -285,167 +187,9 @@ Item { // Wrapper
|
||||
model: ScriptModel {
|
||||
id: model
|
||||
objectProp: "key"
|
||||
values: {
|
||||
// Search results are handled here
|
||||
////////////////// Skip? //////////////////
|
||||
if (root.searchingText == "")
|
||||
return [];
|
||||
|
||||
///////////// Special cases ///////////////
|
||||
if (root.searchingText.startsWith(Config.options.search.prefix.clipboard)) {
|
||||
// Clipboard
|
||||
const searchString = StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.clipboard);
|
||||
return Cliphist.fuzzyQuery(searchString).map((entry, index, array) => {
|
||||
const mightBlurImage = Cliphist.entryIsImage(entry) && root.clipboardWorkSafetyActive;
|
||||
let shouldBlurImage = mightBlurImage;
|
||||
if (mightBlurImage) {
|
||||
shouldBlurImage = shouldBlurImage && (containsUnsafeLink(array[index - 1]) || containsUnsafeLink(array[index + 1]));
|
||||
}
|
||||
const type = `#${entry.match(/^\s*(\S+)/)?.[1] || ""}`
|
||||
return {
|
||||
key: type,
|
||||
cliphistRawString: entry,
|
||||
name: StringUtils.cleanCliphistEntry(entry),
|
||||
clickActionName: "",
|
||||
type: type,
|
||||
execute: () => {
|
||||
Cliphist.copy(entry)
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
name: "Copy",
|
||||
materialIcon: "content_copy",
|
||||
execute: () => {
|
||||
Cliphist.copy(entry);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Delete",
|
||||
materialIcon: "delete",
|
||||
execute: () => {
|
||||
Cliphist.deleteEntry(entry);
|
||||
}
|
||||
}
|
||||
],
|
||||
blurImage: shouldBlurImage,
|
||||
blurImageText: Translation.tr("Work safety")
|
||||
};
|
||||
}).filter(Boolean);
|
||||
}
|
||||
else if (root.searchingText.startsWith(Config.options.search.prefix.emojis)) {
|
||||
// Clipboard
|
||||
const searchString = StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.emojis);
|
||||
return Emojis.fuzzyQuery(searchString).map(entry => {
|
||||
const emoji = entry.match(/^\s*(\S+)/)?.[1] || ""
|
||||
return {
|
||||
key: emoji,
|
||||
cliphistRawString: entry,
|
||||
bigText: emoji,
|
||||
name: entry.replace(/^\s*\S+\s+/, ""),
|
||||
clickActionName: "",
|
||||
type: "Emoji",
|
||||
execute: () => {
|
||||
Quickshell.clipboardText = entry.match(/^\s*(\S+)/)?.[1];
|
||||
}
|
||||
};
|
||||
}).filter(Boolean);
|
||||
}
|
||||
|
||||
////////////////// Init ///////////////////
|
||||
nonAppResultsTimer.restart();
|
||||
const mathResultObject = {
|
||||
key: `Math result: ${root.mathResult}`,
|
||||
name: root.mathResult,
|
||||
clickActionName: Translation.tr("Copy"),
|
||||
type: Translation.tr("Math result"),
|
||||
fontType: "monospace",
|
||||
materialSymbol: 'calculate',
|
||||
execute: () => {
|
||||
Quickshell.clipboardText = root.mathResult;
|
||||
}
|
||||
};
|
||||
const appResultObjects = AppSearch.fuzzyQuery(StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.app)).map(entry => {
|
||||
entry.clickActionName = Translation.tr("Launch");
|
||||
entry.type = Translation.tr("App");
|
||||
entry.key = entry.execute
|
||||
return entry;
|
||||
})
|
||||
const commandResultObject = {
|
||||
key: `cmd ${root.searchingText}`,
|
||||
name: StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.shellCommand).replace("file://", ""),
|
||||
clickActionName: Translation.tr("Run"),
|
||||
type: Translation.tr("Run command"),
|
||||
fontType: "monospace",
|
||||
materialSymbol: 'terminal',
|
||||
execute: () => {
|
||||
let cleanedCommand = root.searchingText.replace("file://", "");
|
||||
cleanedCommand = StringUtils.cleanPrefix(cleanedCommand, Config.options.search.prefix.shellCommand);
|
||||
if (cleanedCommand.startsWith(Config.options.search.prefix.shellCommand)) {
|
||||
cleanedCommand = cleanedCommand.slice(Config.options.search.prefix.shellCommand.length);
|
||||
}
|
||||
Quickshell.execDetached(["bash", "-c", searchingText.startsWith('sudo') ? `${Config.options.apps.terminal} fish -C '${cleanedCommand}'` : cleanedCommand]);
|
||||
}
|
||||
};
|
||||
const webSearchResultObject = {
|
||||
key: `website ${root.searchingText}`,
|
||||
name: StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.webSearch),
|
||||
clickActionName: Translation.tr("Search"),
|
||||
type: Translation.tr("Search the web"),
|
||||
materialSymbol: 'travel_explore',
|
||||
execute: () => {
|
||||
let query = StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.webSearch);
|
||||
let url = Config.options.search.engineBaseUrl + query;
|
||||
for (let site of Config.options.search.excludedSites) {
|
||||
url += ` -site:${site}`;
|
||||
}
|
||||
Qt.openUrlExternally(url);
|
||||
}
|
||||
}
|
||||
const launcherActionObjects = root.searchActions.map(action => {
|
||||
const actionString = `${Config.options.search.prefix.action}${action.action}`;
|
||||
if (actionString.startsWith(root.searchingText) || root.searchingText.startsWith(actionString)) {
|
||||
return {
|
||||
key: `Action ${actionString}`,
|
||||
name: root.searchingText.startsWith(actionString) ? root.searchingText : actionString,
|
||||
clickActionName: Translation.tr("Run"),
|
||||
type: Translation.tr("Action"),
|
||||
materialSymbol: 'settings_suggest',
|
||||
execute: () => {
|
||||
action.execute(root.searchingText.split(" ").slice(1).join(" "));
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}).filter(Boolean);
|
||||
|
||||
//////// Prioritized by prefix /////////
|
||||
let result = [];
|
||||
const startsWithNumber = /^\d/.test(root.searchingText);
|
||||
const startsWithMathPrefix = root.searchingText.startsWith(Config.options.search.prefix.math);
|
||||
const startsWithShellCommandPrefix = root.searchingText.startsWith(Config.options.search.prefix.shellCommand);
|
||||
const startsWithWebSearchPrefix = root.searchingText.startsWith(Config.options.search.prefix.webSearch);
|
||||
if (startsWithNumber || startsWithMathPrefix) {
|
||||
result.push(mathResultObject);
|
||||
} else if (startsWithShellCommandPrefix) {
|
||||
result.push(commandResultObject);
|
||||
} else if (startsWithWebSearchPrefix) {
|
||||
result.push(webSearchResultObject);
|
||||
}
|
||||
|
||||
//////////////// Apps //////////////////
|
||||
result = result.concat(appResultObjects);
|
||||
|
||||
////////// Launcher actions ////////////
|
||||
result = result.concat(launcherActionObjects);
|
||||
|
||||
/// Math result, command, web search ///
|
||||
if (Config.options.search.prefix.showDefaultActionsWithoutPrefix) {
|
||||
if (!startsWithShellCommandPrefix) result.push(commandResultObject);
|
||||
if (!startsWithNumber && !startsWithMathPrefix) result.push(mathResultObject);
|
||||
if (!startsWithWebSearchPrefix) result.push(webSearchResultObject);
|
||||
}
|
||||
|
||||
return result;
|
||||
values: LauncherSearch.results
|
||||
onValuesChanged: {
|
||||
root.focusFirstItem();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ BarButton {
|
||||
}
|
||||
}
|
||||
|
||||
AppIcon {
|
||||
WAppIcon {
|
||||
id: iconWidget
|
||||
anchors.centerIn: parent
|
||||
iconName: root.iconName
|
||||
|
||||
@@ -5,17 +5,12 @@ import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
WButton {
|
||||
AcrylicButton {
|
||||
id: root
|
||||
|
||||
property var altAction: () => {}
|
||||
property var middleClickAction: () => {}
|
||||
|
||||
colBackground: ColorUtils.transparentize(Looks.colors.bg1)
|
||||
colBackgroundHover: Looks.colors.bg1Hover
|
||||
colBackgroundActive: Looks.colors.bg1Active
|
||||
property color colBackgroundBorder
|
||||
property color color
|
||||
Layout.fillHeight: true
|
||||
topInset: 4
|
||||
bottomInset: 4
|
||||
@@ -23,16 +18,7 @@ WButton {
|
||||
rightInset: 0
|
||||
horizontalPadding: 8
|
||||
|
||||
colBackgroundBorder: ColorUtils.transparentize(Looks.colors.bg1Border, (root.checked || root.hovered) ? Looks.backgroundTransparency : 1)
|
||||
color: {
|
||||
if (root.down) {
|
||||
return root.colBackgroundActive
|
||||
} else if ((root.hovered && !root.down) || root.checked) {
|
||||
return root.colBackgroundHover
|
||||
} else {
|
||||
return root.colBackground
|
||||
}
|
||||
}
|
||||
colBackground: ColorUtils.transparentize(Looks.colors.bg1)
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
@@ -50,15 +36,4 @@ WButton {
|
||||
}
|
||||
}
|
||||
|
||||
background: AcrylicRectangle {
|
||||
shiny: ((root.hovered && !root.down) || root.checked)
|
||||
color: root.color
|
||||
radius: Looks.radius.medium
|
||||
border.width: 1
|
||||
border.color: root.colBackgroundBorder
|
||||
|
||||
Behavior on border.color {
|
||||
animation: Looks.transition.color.createObject(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,14 +7,16 @@ import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
// TODO: Replace the icon with QMLized svg (with /usr/lib/qt6/bin/svgtoqml) for proper micro-animation
|
||||
AppButton {
|
||||
id: root
|
||||
|
||||
leftInset: Config.options.waffles.bar.leftAlignApps ? 12 : 0
|
||||
iconName: down ? "start-here-pressed" : "start-here"
|
||||
|
||||
checked: GlobalStates.searchOpen
|
||||
onClicked: {
|
||||
GlobalStates.overviewOpen = !GlobalStates.overviewOpen; // For now...
|
||||
GlobalStates.searchOpen = !GlobalStates.searchOpen;
|
||||
}
|
||||
|
||||
BarToolTip {
|
||||
|
||||
@@ -42,7 +42,7 @@ AppButton {
|
||||
}
|
||||
spacing: 6
|
||||
|
||||
AppIcon {
|
||||
WAppIcon {
|
||||
id: iconWidget
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
iconName: root.iconName
|
||||
|
||||
@@ -43,7 +43,7 @@ Button {
|
||||
Layout.fillHeight: false
|
||||
spacing: 8
|
||||
|
||||
AppIcon {
|
||||
WAppIcon {
|
||||
id: appIcon
|
||||
Layout.leftMargin: Looks.radius.large - root.padding + 2
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
WButton {
|
||||
id: root
|
||||
|
||||
colBackground: Looks.colors.bg1
|
||||
colBackgroundHover: Looks.colors.bg1Hover
|
||||
colBackgroundActive: Looks.colors.bg1Active
|
||||
property color colBackgroundBorder
|
||||
property color color
|
||||
property alias border: background.border
|
||||
property alias shinyColor: background.borderColor
|
||||
|
||||
colBackgroundBorder: ColorUtils.transparentize(color, (root.checked || root.hovered) ? Looks.backgroundTransparency : 0)
|
||||
color: {
|
||||
if (root.down) {
|
||||
return root.colBackgroundActive
|
||||
} else if ((root.hovered && !root.down) || root.checked) {
|
||||
return root.colBackgroundHover
|
||||
} else {
|
||||
return root.colBackground
|
||||
}
|
||||
}
|
||||
|
||||
background: AcrylicRectangle {
|
||||
id: background
|
||||
shiny: ((root.hovered && !root.down) || root.checked)
|
||||
color: root.color
|
||||
radius: Looks.radius.medium
|
||||
border.width: 1
|
||||
border.color: root.colBackgroundBorder
|
||||
|
||||
Behavior on border.color {
|
||||
animation: Looks.transition.color.createObject(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,16 +9,17 @@ Rectangle {
|
||||
id: root
|
||||
|
||||
property bool shiny: true // Top border
|
||||
property color borderColor: ColorUtils.transparentize(Looks.colors.bg2Border, shiny ? 0.5 : 1)
|
||||
property color borderColor: ColorUtils.transparentize(Looks.colors.bg1Hover, 0.7)
|
||||
property color internalBorderColor: ColorUtils.transparentize(borderColor, shiny ? 0.0 : 1)
|
||||
color: Looks.colors.bg1Hover
|
||||
radius: Looks.radius.medium
|
||||
Behavior on color {
|
||||
animation: Looks.transition.color.createObject(this)
|
||||
}
|
||||
Behavior on borderColor {
|
||||
Behavior on internalBorderColor {
|
||||
animation: Looks.transition.color.createObject(this)
|
||||
}
|
||||
onBorderColorChanged: {
|
||||
onInternalBorderColorChanged: {
|
||||
borderCanvas.requestPaint();
|
||||
}
|
||||
|
||||
@@ -32,7 +33,7 @@ Rectangle {
|
||||
var ctx = getContext("2d");
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
var borderColor = root.borderColor;
|
||||
var borderColor = root.internalBorderColor;
|
||||
|
||||
var r = root.radius;
|
||||
var fadeLength = Math.max(1, r);
|
||||
|
||||
@@ -53,6 +53,8 @@ Singleton {
|
||||
property color controlBgHover: '#57575B'
|
||||
property color controlFg: "#FFFFFF"
|
||||
property color accentUnfocused: "#848484"
|
||||
property color link: "#235CCF"
|
||||
property color inputBg: ColorUtils.transparentize(bg0, 0.4)
|
||||
}
|
||||
darkColors: QtObject {
|
||||
id: darkColors
|
||||
@@ -70,7 +72,7 @@ Singleton {
|
||||
property color bg2: '#8a8a8a'
|
||||
property color bg2Hover: '#b1b1b1'
|
||||
property color bg2Active: '#919191'
|
||||
property color bg2Border: '#c4c4c4'
|
||||
property color bg2Border: '#bdbdbd'
|
||||
property color subfg: "#CED1D7"
|
||||
property color fg: "#FFFFFF"
|
||||
property color fg1: "#D1D1D1"
|
||||
@@ -80,6 +82,8 @@ Singleton {
|
||||
property color controlBgHover: "#CFCED1"
|
||||
property color controlFg: "#454545"
|
||||
property color accentUnfocused: "#989898"
|
||||
property color link: "#A7C9FC"
|
||||
property color inputBg: ColorUtils.transparentize(darkColors.bg0, 0.5)
|
||||
}
|
||||
colors: QtObject {
|
||||
id: colors
|
||||
@@ -110,6 +114,8 @@ Singleton {
|
||||
property color controlBg: root.dark ? root.darkColors.controlBg : root.lightColors.controlBg
|
||||
property color controlBgHover: root.dark ? root.darkColors.controlBgHover : root.lightColors.controlBgHover
|
||||
property color controlFg: root.dark ? root.darkColors.controlFg : root.lightColors.controlFg
|
||||
property color inputBg: root.dark ? root.darkColors.inputBg : root.lightColors.inputBg
|
||||
property color link: root.dark ? root.darkColors.link : root.lightColors.link
|
||||
property color danger: "#C42B1C"
|
||||
property color dangerActive: "#B62D1F"
|
||||
property color warning: "#FF9900"
|
||||
@@ -118,6 +124,7 @@ Singleton {
|
||||
property color accentActive: Appearance.colors.colPrimaryActive
|
||||
property color accentUnfocused: root.dark ? root.darkColors.accentUnfocused : root.lightColors.accentUnfocused
|
||||
property color accentFg: ColorUtils.isDark(accent) ? "#FFFFFF" : "#000000"
|
||||
property color selection: Appearance.colors.colPrimaryContainer
|
||||
}
|
||||
|
||||
radius: QtObject {
|
||||
|
||||
@@ -2,7 +2,6 @@ import QtQuick
|
||||
import org.kde.kirigami as Kirigami
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
Kirigami.Icon {
|
||||
id: root
|
||||
@@ -53,10 +53,11 @@ Button {
|
||||
// Hover stuff
|
||||
signal hoverTimedOut
|
||||
property bool shouldShowTooltip: false
|
||||
ToolTip.delay: 400
|
||||
property Timer hoverTimer: Timer {
|
||||
id: hoverTimer
|
||||
running: root.hovered
|
||||
interval: 400
|
||||
interval: root.ToolTip.delay
|
||||
onTriggered: {
|
||||
root.hoverTimedOut();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ import qs.services
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
function pathForName(iconName) {
|
||||
return Quickshell.shellPath(`assets/icons/fluent/${iconName}.svg`);
|
||||
}
|
||||
|
||||
function wifiIconForStrength(strength) {
|
||||
if (strength > 75)
|
||||
return "wifi-1";
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
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
|
||||
|
||||
Menu {
|
||||
id: root
|
||||
|
||||
property bool downDirection: false
|
||||
property bool hasIcons: false // TODO: implement
|
||||
|
||||
implicitWidth: background.implicitWidth + root.padding * 2
|
||||
implicitHeight: background.implicitHeight + root.padding * 2
|
||||
padding: 3
|
||||
property real sourceEdgeMargin: -implicitHeight
|
||||
clip: true
|
||||
|
||||
enter: Transition {
|
||||
NumberAnimation {
|
||||
property: "sourceEdgeMargin"
|
||||
from: -root.implicitHeight
|
||||
to: root.padding
|
||||
duration: 200
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
|
||||
}
|
||||
}
|
||||
exit: Transition {
|
||||
NumberAnimation {
|
||||
property: "sourceEdgeMargin"
|
||||
from: root.padding
|
||||
to: -root.implicitHeight
|
||||
duration: 150
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeOut
|
||||
}
|
||||
}
|
||||
|
||||
background: WPane {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: root.downDirection ? parent.top : undefined
|
||||
bottom: root.downDirection ? undefined : parent.bottom
|
||||
margins: root.padding
|
||||
topMargin: root.downDirection ? root.sourceEdgeMargin : root.padding
|
||||
bottomMargin: root.downDirection ? root.padding : root.sourceEdgeMargin
|
||||
}
|
||||
contentItem: Rectangle {
|
||||
color: Looks.colors.bg1Base
|
||||
implicitWidth: menuListView.implicitWidth + root.padding * 2
|
||||
implicitHeight: root.contentItem.implicitHeight + root.padding * 2
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: ListView {
|
||||
id: menuListView
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: root.downDirection ? parent.top : undefined
|
||||
bottom: root.downDirection ? undefined : parent.bottom
|
||||
margins: root.padding * 2
|
||||
topMargin: root.downDirection ? root.sourceEdgeMargin : root.padding
|
||||
bottomMargin: root.downDirection ? root.padding : root.sourceEdgeMargin
|
||||
}
|
||||
implicitHeight: contentHeight
|
||||
implicitWidth: Array.from({
|
||||
length: count
|
||||
}, (_, i) => itemAtIndex(i)?.implicitWidth ?? 0).reduce((a, b) => a > b ? a : b)
|
||||
|
||||
model: root.contentModel
|
||||
}
|
||||
|
||||
delegate: WMenuItem {
|
||||
id: menuItemDelegate
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
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
|
||||
|
||||
MenuItem {
|
||||
id: root
|
||||
|
||||
property color colBackground: ColorUtils.transparentize(Looks.colors.bg1)
|
||||
property color colBackgroundHover: Looks.colors.bg2Hover
|
||||
property color colBackgroundActive: Looks.colors.bg2Active
|
||||
property color colBackgroundToggled: Looks.colors.accent
|
||||
property color colBackgroundToggledHover: Looks.colors.accentHover
|
||||
property color colBackgroundToggledActive: Looks.colors.accentActive
|
||||
property color colForeground: Looks.colors.fg
|
||||
property color colForegroundToggled: Looks.colors.accentFg
|
||||
property color colForegroundDisabled: ColorUtils.transparentize(Looks.colors.subfg, 0.4)
|
||||
property color color: {
|
||||
if (!root.enabled)
|
||||
return colBackground;
|
||||
if (root.checked) {
|
||||
if (root.down) {
|
||||
return root.colBackgroundToggledActive;
|
||||
} else if (root.hovered) {
|
||||
return root.colBackgroundToggledHover;
|
||||
} else {
|
||||
return root.colBackgroundToggled;
|
||||
}
|
||||
}
|
||||
if (root.down) {
|
||||
return root.colBackgroundActive;
|
||||
} else if (root.hovered) {
|
||||
return root.colBackgroundHover;
|
||||
} else {
|
||||
return root.colBackground;
|
||||
}
|
||||
}
|
||||
property color fgColor: {
|
||||
if (root.checked)
|
||||
return root.colForegroundToggled;
|
||||
if (root.enabled)
|
||||
return root.colForeground;
|
||||
return root.colForegroundDisabled;
|
||||
}
|
||||
|
||||
property real inset: 2
|
||||
topInset: inset
|
||||
bottomInset: inset
|
||||
leftInset: inset
|
||||
rightInset: inset
|
||||
horizontalPadding: 11
|
||||
|
||||
background: Rectangle {
|
||||
id: backgroundRect
|
||||
radius: Looks.radius.medium
|
||||
color: root.color
|
||||
Behavior on color {
|
||||
animation: Looks.transition.color.createObject(this)
|
||||
}
|
||||
}
|
||||
|
||||
implicitHeight: Math.max(28, contentItem.implicitHeight) + topInset + bottomInset
|
||||
implicitWidth: contentItem.implicitWidth + leftInset + rightInset + leftPadding + rightPadding
|
||||
|
||||
contentItem: RowLayout {
|
||||
id: contentLayout
|
||||
spacing: 12
|
||||
FluentIcon {
|
||||
id: buttonIcon
|
||||
monochrome: true
|
||||
implicitSize: 20
|
||||
Layout.fillWidth: false
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
color: root.fgColor
|
||||
visible: root.icon.name !== "";
|
||||
icon: root.icon.name
|
||||
}
|
||||
WText {
|
||||
id: buttonText
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
text: root.text
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.pixelSize: Looks.font.pixelSize.large
|
||||
color: root.fgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import qs.modules.waffle.looks
|
||||
|
||||
Item {
|
||||
id: root
|
||||
required property Item contentItem
|
||||
property Item contentItem
|
||||
property real radius: Looks.radius.large
|
||||
property alias border: borderRect
|
||||
property alias borderColor: borderRect.border.color
|
||||
|
||||
@@ -8,8 +8,11 @@ Text {
|
||||
color: Looks.colors.fg
|
||||
|
||||
font {
|
||||
hintingPreference: Font.PreferFullHinting
|
||||
family: Looks.font.family.ui
|
||||
pixelSize: Looks.font.pixelSize.normal
|
||||
weight: Looks.font.weight.regular
|
||||
}
|
||||
|
||||
linkColor: Looks.colors.link
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
TextInput {
|
||||
id: root
|
||||
renderType: Text.NativeRendering
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: Looks.colors.fg
|
||||
|
||||
font {
|
||||
hintingPreference: Font.PreferFullHinting
|
||||
family: Looks.font.family.ui
|
||||
pixelSize: Looks.font.pixelSize.large
|
||||
weight: Looks.font.weight.regular
|
||||
}
|
||||
|
||||
selectionColor: Looks.colors.selection
|
||||
}
|
||||
@@ -25,6 +25,8 @@ StyledToolTip {
|
||||
verticalPadding: 8
|
||||
horizontalPadding: 10
|
||||
|
||||
delay: 400
|
||||
|
||||
contentItem: WToolTipContent {
|
||||
id: tooltipContent
|
||||
realContentItem: root.realContentItem
|
||||
|
||||
@@ -6,6 +6,7 @@ Item {
|
||||
id: root
|
||||
anchors.centerIn: parent
|
||||
required property Item realContentItem
|
||||
property alias radius: realContent.radius
|
||||
property real verticalPadding: 8
|
||||
property real horizontalPadding: 10
|
||||
implicitWidth: realContent.implicitWidth + 2 * 2
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import Quickshell
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
StyledImage {
|
||||
id: avatar
|
||||
Layout.alignment: Qt.AlignTop
|
||||
sourceSize: Qt.size(32, 32)
|
||||
source: Directories.userAvatarPathAccountsService
|
||||
fallbacks: [Directories.userAvatarPathRicersAndWeirdSystems, Directories.userAvatarPathRicersAndWeirdSystems2]
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Circle {
|
||||
diameter: avatar.height
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ WBarAttachedPanelContent {
|
||||
property bool collapsed: false
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
id: contentLayout
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: parent.top
|
||||
@@ -41,9 +42,24 @@ WBarAttachedPanelContent {
|
||||
}
|
||||
contentItem: NotificationPaneContent {
|
||||
implicitWidth: calendarColumnLayout.implicitWidth
|
||||
implicitHeight: Notifications.list.length > 0 ? (notificationArea.height - notificationPane.borderWidth * 2) : 230
|
||||
implicitHeight: {
|
||||
if (Notifications.list.length > 0) {
|
||||
return ((contentLayout.height - calendarPane.height - contentLayout.spacing) - notificationPane.borderWidth * 2)
|
||||
}
|
||||
return 230;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: enableTimer
|
||||
interval: Config.options.hacks.arbitraryRaceConditionDelay
|
||||
onTriggered: heightBehavior.enabled = true;
|
||||
}
|
||||
Behavior on implicitHeight {
|
||||
id: heightBehavior
|
||||
enabled: false
|
||||
Component.onCompleted: {
|
||||
enableTimer.restart();
|
||||
}
|
||||
animation: Looks.transition.enter.createObject(this)
|
||||
}
|
||||
}
|
||||
@@ -51,9 +67,9 @@ WBarAttachedPanelContent {
|
||||
}
|
||||
|
||||
WPane {
|
||||
contentItem: ColumnLayout {
|
||||
id: calendarPane
|
||||
contentItem: WPanelPageColumn {
|
||||
id: calendarColumnLayout
|
||||
spacing: 0
|
||||
DateHeader {
|
||||
Layout.fillWidth: true
|
||||
Synchronizer on collapsed {
|
||||
|
||||
@@ -8,18 +8,24 @@ import qs.modules.common.functions
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
WBorderlessButton {
|
||||
id: headerButton
|
||||
id: root
|
||||
Layout.fillWidth: false
|
||||
implicitWidth: 16
|
||||
implicitHeight: 16
|
||||
property real implicitSize: 16
|
||||
implicitWidth: implicitSize
|
||||
implicitHeight: implicitSize
|
||||
color: "transparent"
|
||||
colForeground: root.hovered && !root.pressed ? Looks.colors.fg : Looks.colors.fg1
|
||||
|
||||
Behavior on colForeground {
|
||||
animation: Looks.transition.color.createObject(this)
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
FluentIcon {
|
||||
anchors.centerIn: parent
|
||||
implicitSize: 16
|
||||
icon: headerButton.icon.name
|
||||
color: headerButton.hovered && !headerButton.pressed ? Looks.colors.fg : Looks.colors.fg1
|
||||
implicitSize: root.implicitSize
|
||||
icon: root.icon.name
|
||||
color: root.colForeground
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,27 @@ import QtQuick
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
SmallBorderedIconButton {
|
||||
AcrylicButton {
|
||||
id: root
|
||||
|
||||
property bool iconVisible: true
|
||||
property string iconName: ""
|
||||
property bool iconFilled: true
|
||||
|
||||
colBackground: Looks.colors.bg2
|
||||
colBackgroundHover: Looks.colors.bg2Hover
|
||||
colBackgroundActive: Looks.colors.bg2Active
|
||||
property color colBorder: Looks.colors.bg2Border
|
||||
property color colBorderToggled: Looks.colors.accent
|
||||
border.color: checked ? colBorderToggled : colBorder
|
||||
|
||||
leftPadding: 12
|
||||
rightPadding: 12
|
||||
implicitWidth: focusButtonContent.implicitWidth + leftPadding + rightPadding
|
||||
implicitHeight: 24
|
||||
|
||||
contentItem: Row {
|
||||
id: focusButtonContent
|
||||
|
||||
@@ -7,11 +7,13 @@ import qs.modules.common.widgets
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
// TODO: Swipe to dismiss
|
||||
MouseArea {
|
||||
id: root
|
||||
|
||||
required property var notificationGroup
|
||||
readonly property var notifications: notificationGroup?.notifications ?? []
|
||||
property bool expanded: false
|
||||
|
||||
implicitWidth: contentLayout.implicitWidth
|
||||
implicitHeight: contentLayout.implicitHeight
|
||||
@@ -34,12 +36,23 @@ MouseArea {
|
||||
interactive: false
|
||||
spacing: 4
|
||||
model: ScriptModel {
|
||||
values: root.notifications.slice().reverse()
|
||||
values: root.expanded ? root.notifications.slice().reverse() : root.notifications.slice(-1)
|
||||
objectProp: "notificationId"
|
||||
}
|
||||
delegate: WSingleNotification {
|
||||
required property int index
|
||||
required property var modelData
|
||||
width: ListView.view.width
|
||||
notification: modelData
|
||||
groupExpandControlMessage: {
|
||||
if (root.notifications.length <= 1) return "";
|
||||
if (!root.expanded) return Translation.tr("+%1 notifications").arg(root.notifications.length - 1);
|
||||
if (index === root.notifications.length - 1) return Translation.tr("See fewer");
|
||||
return "";
|
||||
}
|
||||
onGroupExpandToggle: {
|
||||
root.expanded = !root.expanded;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
@@ -12,11 +13,18 @@ MouseArea {
|
||||
id: root
|
||||
|
||||
required property var notification
|
||||
property bool expanded: false
|
||||
property bool expanded: notification.actions.length > 0
|
||||
property string groupExpandControlMessage: ""
|
||||
signal groupExpandToggle
|
||||
hoverEnabled: true
|
||||
|
||||
implicitHeight: contentItem.implicitHeight
|
||||
implicitWidth: contentItem.implicitWidth
|
||||
|
||||
Behavior on implicitHeight {
|
||||
animation: Looks.transition.enter.createObject(this)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: contentItem
|
||||
anchors.fill: parent
|
||||
@@ -26,34 +34,205 @@ MouseArea {
|
||||
implicitHeight: notificationContent.implicitHeight + padding * 2
|
||||
implicitWidth: notificationContent.implicitWidth + padding * 2
|
||||
border.width: 1
|
||||
border.color: Looks.applyContentTransparency(Looks.colors.ambientShadow)
|
||||
border.color: ColorUtils.applyAlpha(Looks.colors.ambientShadow, 0.1)
|
||||
|
||||
ColumnLayout {
|
||||
id: notificationContent
|
||||
anchors.fill: parent
|
||||
anchors.margins: contentItem.padding
|
||||
spacing: 19
|
||||
|
||||
RowLayout {
|
||||
// Header
|
||||
SingleNotificationHeader {
|
||||
Layout.fillWidth: true
|
||||
WText {
|
||||
text: NotificationUtils.getFriendlyNotifTimeString(root.notification?.time)
|
||||
}
|
||||
|
||||
// Content
|
||||
Item {
|
||||
id: actualContent
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
property real spacing: 16
|
||||
implicitHeight: Math.max(contentColumn.implicitHeight, imageLoader.height)
|
||||
implicitWidth: contentColumn.implicitWidth
|
||||
|
||||
Loader {
|
||||
id: imageLoader
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
}
|
||||
active: root.notification.image != ""
|
||||
sourceComponent: StyledImage {
|
||||
readonly property int size: 48
|
||||
width: size
|
||||
height: size
|
||||
sourceSize.width: size
|
||||
sourceSize.height: size
|
||||
source: root.notification.image
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: contentColumn
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
spacing: 3
|
||||
|
||||
SummaryText {
|
||||
id: summaryText
|
||||
Layout.leftMargin: imageLoader.active ? imageLoader.width + actualContent.spacing : 0
|
||||
}
|
||||
BodyText {
|
||||
Layout.leftMargin: imageLoader.active ? imageLoader.width + actualContent.spacing : 0
|
||||
// onLineLaidOut: (line) => {
|
||||
// if (!imageLoader.active) return;
|
||||
// const dodgeDistance = imageLoader.width + actualContent.spacing;
|
||||
// // print(line.y, dodgeDistance)
|
||||
// if (summaryText.height + line.y > dodgeDistance) {
|
||||
// line.x -= dodgeDistance;
|
||||
// line.width += dodgeDistance;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
// Actions
|
||||
ActionsRow {
|
||||
Layout.fillWidth: true
|
||||
WText {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
text: root.notification.summary
|
||||
}
|
||||
WText {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
// "+1 notifications" button
|
||||
GroupExpandButton {
|
||||
Layout.bottomMargin: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component SingleNotificationHeader: RowLayout {
|
||||
ExpandButton {
|
||||
Layout.topMargin: -2
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NotificationHeaderButton {
|
||||
Layout.rightMargin: 4
|
||||
opacity: root.containsMouse ? 1 : 0
|
||||
icon.name: "dismiss"
|
||||
implicitSize: 12
|
||||
onClicked: {
|
||||
Qt.callLater(() => {
|
||||
Notifications.discardNotification(root.notification?.notificationId);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component ActionsRow: RowLayout {
|
||||
visible: root.expanded && root.notification.actions.length > 0
|
||||
uniformCellSizes: true
|
||||
Repeater {
|
||||
id: actionRepeater
|
||||
model: root.notification.actions
|
||||
delegate: WBorderedButton {
|
||||
id: actionButton
|
||||
Layout.fillHeight: true
|
||||
required property var modelData
|
||||
Layout.fillWidth: true
|
||||
verticalPadding: 16
|
||||
horizontalPadding: 12
|
||||
text: modelData.text
|
||||
implicitHeight: actionButtonText.implicitHeight + verticalPadding * 2
|
||||
contentItem: WText {
|
||||
id: actionButtonText
|
||||
text: actionButton.text
|
||||
font.pixelSize: Looks.font.pixelSize.large
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: root.expanded ? 100 : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component SummaryText: WText {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
text: root.notification?.summary
|
||||
font.pixelSize: Looks.font.pixelSize.large
|
||||
}
|
||||
|
||||
component BodyText: WText {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignTop
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: root.expanded ? 100 : 1
|
||||
text: {
|
||||
if (root.expanded)
|
||||
return `<style>img{max-width:${summaryText.width}px; align: right}</style>` + `${NotificationUtils.processNotificationBody(root.notification.body, root.notification.appName || root.notification.summary).replace(/\n/g, "<br/>")}`;
|
||||
return NotificationUtils.processNotificationBody(root.notification.body, root.notification.appName || root.notification.summary).replace(/\n/g, "<br/>");
|
||||
}
|
||||
color: Looks.colors.subfg
|
||||
textFormat: root.expanded ? Text.RichText : Text.StyledText
|
||||
onLinkActivated: link => {
|
||||
Qt.openUrlExternally(link);
|
||||
GlobalStates.sidebarRightOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
component ExpandButton: NotificationHeaderButton {
|
||||
id: expandButton
|
||||
implicitWidth: expandButtonContent.implicitWidth
|
||||
onClicked: root.expanded = !root.expanded
|
||||
|
||||
contentItem: Item {
|
||||
id: expandButtonContent
|
||||
implicitWidth: expandButtonRow.implicitWidth
|
||||
implicitHeight: expandButtonRow.implicitHeight
|
||||
RowLayout {
|
||||
id: expandButtonRow
|
||||
anchors.centerIn: parent
|
||||
spacing: 8
|
||||
WText {
|
||||
color: expandButton.colForeground
|
||||
text: NotificationUtils.getFriendlyNotifTimeString(root.notification?.time)
|
||||
}
|
||||
FluentIcon {
|
||||
Layout.rightMargin: 12
|
||||
icon: "chevron-down"
|
||||
implicitSize: 18
|
||||
rotation: root.expanded ? -180 : 0
|
||||
color: expandButton.colForeground
|
||||
Behavior on rotation {
|
||||
animation: Looks.transition.rotate.createObject(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component GroupExpandButton: AcrylicButton {
|
||||
id: groupExpandButton
|
||||
visible: root.groupExpandControlMessage !== ""
|
||||
horizontalPadding: 10
|
||||
implicitHeight: 24
|
||||
implicitWidth: expandButtonText.implicitWidth + horizontalPadding * 2
|
||||
onClicked: root.groupExpandToggle()
|
||||
contentItem: Item {
|
||||
WText {
|
||||
id: expandButtonText
|
||||
anchors.centerIn: parent
|
||||
text: root.groupExpandControlMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
FooterRectangle {
|
||||
id: root
|
||||
|
||||
property bool searching: text.length > 0
|
||||
property alias text: searchInput.text
|
||||
|
||||
Component.onCompleted: searchInput.forceActiveFocus()
|
||||
|
||||
focus: true
|
||||
color: searching ? Looks.colors.bgPanelBody : Looks.colors.bgPanelFooter
|
||||
|
||||
implicitWidth: 832 // TODO: Make sizes naturally inferred
|
||||
implicitHeight: 63
|
||||
|
||||
Rectangle {
|
||||
id: outline
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: 32
|
||||
rightMargin: 32
|
||||
topMargin: 16
|
||||
bottomMargin: 15
|
||||
}
|
||||
color: "transparent"
|
||||
radius: height / 2
|
||||
border.width: 1
|
||||
border.color: Looks.colors.bg2Border
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: searchInputBg
|
||||
anchors.fill: outline
|
||||
anchors.margins: 1
|
||||
radius: height / 2
|
||||
color: Looks.colors.inputBg
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 11
|
||||
|
||||
WAppIcon {
|
||||
Layout.leftMargin: 14
|
||||
iconName: "system-search-checked"
|
||||
separateLightDark: true
|
||||
implicitSize: 18
|
||||
}
|
||||
|
||||
WTextInput {
|
||||
id: searchInput
|
||||
focus: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
WText {
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
color: Looks.colors.accentUnfocused
|
||||
text: Translation.tr("Search for apps") // should also have "", settings, and documents" but we don't have those
|
||||
visible: searchInput.text.length === 0
|
||||
font.pixelSize: Looks.font.pixelSize.large
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.IBeamCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
BodyRectangle {
|
||||
id: root
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import Qt.labs.synchronizer
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
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
|
||||
|
||||
property bool searching: false
|
||||
property string searchText: ""
|
||||
|
||||
contentItem: WPane {
|
||||
contentItem: WPanelPageColumn {
|
||||
SearchBar {
|
||||
focus: true
|
||||
Layout.fillWidth: true
|
||||
Synchronizer on searching {
|
||||
property alias target: root.searching
|
||||
}
|
||||
Synchronizer on text {
|
||||
property alias source: root.searchText
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: pageContentLoader
|
||||
Layout.fillWidth: true
|
||||
source: root.searching ? "SearchPageContent.qml" : "StartPageContent.qml"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import Quickshell
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
WPanelPageColumn {
|
||||
id: root
|
||||
|
||||
WPanelSeparator {}
|
||||
|
||||
BodyRectangle {
|
||||
implicitHeight: 736 // TODO: Make sizes naturally inferred
|
||||
}
|
||||
|
||||
WPanelSeparator {}
|
||||
|
||||
StartFooter {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
component StartFooter: FooterRectangle {
|
||||
implicitHeight: 63
|
||||
|
||||
UserButton {
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: 52
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 12
|
||||
}
|
||||
}
|
||||
|
||||
PowerButton {
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: 52
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component UserButton: WBorderlessButton {
|
||||
id: userButton
|
||||
implicitWidth: userButtonRow.implicitWidth + 12 * 2
|
||||
implicitHeight: 40
|
||||
|
||||
contentItem: Item {
|
||||
RowLayout {
|
||||
id: userButtonRow
|
||||
anchors.centerIn: parent
|
||||
spacing: 12
|
||||
|
||||
WUserAvatar {
|
||||
sourceSize: Qt.size(32, 32)
|
||||
}
|
||||
WText {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: SystemInfo.username
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
userMenu.open();
|
||||
}
|
||||
|
||||
WToolTip {
|
||||
text: SystemInfo.username
|
||||
}
|
||||
|
||||
Popup {
|
||||
id: userMenu
|
||||
x: -51
|
||||
y: -userMenu.implicitHeight + userButton.implicitHeight / 2 - 10
|
||||
|
||||
background: null
|
||||
|
||||
WToolTipContent {
|
||||
id: popupContent
|
||||
horizontalPadding: 10
|
||||
verticalPadding: 7
|
||||
radius: Looks.radius.large
|
||||
realContentItem: Item {
|
||||
implicitWidth: userMenuContentLayout.implicitWidth
|
||||
implicitHeight: userMenuContentLayout.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: userMenuContentLayout
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: popupContent.horizontalPadding
|
||||
rightMargin: popupContent.horizontalPadding
|
||||
topMargin: popupContent.verticalPadding
|
||||
bottomMargin: popupContent.verticalPadding
|
||||
}
|
||||
spacing: 5
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 6
|
||||
FluentIcon {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
implicitSize: 22
|
||||
icon: "corporation"
|
||||
monochrome: false
|
||||
}
|
||||
WText {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: "Megahard"
|
||||
font.pixelSize: Looks.font.pixelSize.large
|
||||
font.weight: Looks.font.weight.strong
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
WBorderlessButton {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
implicitHeight: 36
|
||||
implicitWidth: textItem.implicitWidth + 10 * 2
|
||||
contentItem: WText {
|
||||
id: textItem
|
||||
text: Translation.tr("Sign out")
|
||||
font.pixelSize: Looks.font.pixelSize.large
|
||||
}
|
||||
onClicked: Session.logout()
|
||||
}
|
||||
}
|
||||
Item { // Force min width 360 (using min on the item somehow doesn't work)
|
||||
implicitWidth: 334
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 7
|
||||
Layout.leftMargin: 6
|
||||
spacing: 12
|
||||
WUserAvatar {
|
||||
sourceSize: Qt.size(58, 58)
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 2
|
||||
WText {
|
||||
text: SystemInfo.username
|
||||
font.pixelSize: Looks.font.pixelSize.larger
|
||||
font.weight: Looks.font.weight.strong
|
||||
}
|
||||
WText {
|
||||
color: Looks.colors.fg1
|
||||
text: Translation.tr("Local account")
|
||||
}
|
||||
WText {
|
||||
color: Looks.colors.accent
|
||||
text: Translation.tr("Manage my account")
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
Quickshell.execDetached(["bash", "-c", Config.options.apps.manageUser])
|
||||
GlobalStates.searchOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component PowerButton: WBorderlessButton {
|
||||
id: powerButton
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
|
||||
contentItem: Item {
|
||||
FluentIcon {
|
||||
anchors.centerIn: parent
|
||||
icon: "power"
|
||||
implicitSize: 20
|
||||
}
|
||||
}
|
||||
|
||||
WToolTip {
|
||||
extraVisibleCondition: !powerMenu.visible
|
||||
text: qsTr("Power")
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
powerMenu.open()
|
||||
}
|
||||
|
||||
WMenu {
|
||||
id: powerMenu
|
||||
x: -powerMenu.implicitWidth / 2 + powerButton.implicitWidth / 2
|
||||
y: -powerMenu.implicitHeight - 4
|
||||
Action {
|
||||
icon.name: "lock-closed"
|
||||
text: Translation.tr("Lock")
|
||||
onTriggered: Session.lock()
|
||||
}
|
||||
Action {
|
||||
icon.name: "weather-moon"
|
||||
text: Translation.tr("Sleep")
|
||||
onTriggered: Session.suspend()
|
||||
}
|
||||
Action {
|
||||
icon.name: "power"
|
||||
text: Translation.tr("Shut down")
|
||||
onTriggered: Session.poweroff()
|
||||
}
|
||||
Action {
|
||||
icon.name: "arrow-counterclockwise"
|
||||
text: Translation.tr("Restart")
|
||||
onTriggered: Session.reboot()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
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 onSearchOpenChanged() {
|
||||
if (GlobalStates.searchOpen)
|
||||
panelLoader.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: panelLoader
|
||||
active: GlobalStates.searchOpen
|
||||
sourceComponent: PanelWindow {
|
||||
id: panelWindow
|
||||
exclusiveZone: 0
|
||||
WlrLayershell.namespace: "quickshell:wStartMenu"
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||
color: "transparent"
|
||||
|
||||
anchors {
|
||||
bottom: Config.options.waffles.bar.bottom
|
||||
top: !Config.options.waffles.bar.bottom
|
||||
left: Config.options.waffles.bar.leftAlignApps
|
||||
}
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
HyprlandFocusGrab {
|
||||
id: focusGrab
|
||||
active: true
|
||||
windows: [panelWindow]
|
||||
onCleared: content.close()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: GlobalStates
|
||||
function onSearchOpenChanged() {
|
||||
if (!GlobalStates.searchOpen)
|
||||
content.close();
|
||||
}
|
||||
}
|
||||
|
||||
StartMenuContent {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
|
||||
onClosed: {
|
||||
GlobalStates.searchOpen = false;
|
||||
panelLoader.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "search"
|
||||
|
||||
function toggle() {
|
||||
GlobalStates.searchOpen = !GlobalStates.searchOpen;
|
||||
}
|
||||
function close() {
|
||||
GlobalStates.searchOpen = false;
|
||||
}
|
||||
function open() {
|
||||
GlobalStates.searchOpen = true;
|
||||
}
|
||||
function toggleReleaseInterrupt() {
|
||||
GlobalStates.superReleaseMightTrigger = false;
|
||||
}
|
||||
}
|
||||
|
||||
GlobalShortcut {
|
||||
name: "searchToggle"
|
||||
description: "Toggles search on press"
|
||||
|
||||
onPressed: {
|
||||
GlobalStates.searchOpen = !GlobalStates.searchOpen;
|
||||
}
|
||||
}
|
||||
GlobalShortcut {
|
||||
name: "searchToggleRelease"
|
||||
description: "Toggles search on release"
|
||||
|
||||
onPressed: {
|
||||
GlobalStates.superReleaseMightTrigger = true;
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
if (!GlobalStates.superReleaseMightTrigger) {
|
||||
GlobalStates.superReleaseMightTrigger = true;
|
||||
return;
|
||||
}
|
||||
GlobalStates.searchOpen = !GlobalStates.searchOpen;
|
||||
}
|
||||
}
|
||||
GlobalShortcut {
|
||||
name: "searchToggleReleaseInterrupt"
|
||||
description: "Interrupts possibility of search being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything."
|
||||
|
||||
onPressed: {
|
||||
GlobalStates.superReleaseMightTrigger = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
pragma Singleton
|
||||
|
||||
import qs.modules.common
|
||||
import qs.modules.common.models
|
||||
import qs.modules.common.functions
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property string query: ""
|
||||
property var searchActions: [
|
||||
{
|
||||
action: "accentcolor",
|
||||
execute: args => {
|
||||
Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--noswitch", "--color", ...(args != '' ? [`${args}`] : [])]);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "dark",
|
||||
execute: () => {
|
||||
Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "dark", "--noswitch"]);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "konachanwallpaper",
|
||||
execute: () => {
|
||||
Quickshell.execDetached([Quickshell.shellPath("scripts/colors/random/random_konachan_wall.sh")]);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "light",
|
||||
execute: () => {
|
||||
Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "light", "--noswitch"]);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "superpaste",
|
||||
execute: args => {
|
||||
if (!/^(\d+)/.test(args.trim())) {
|
||||
// Invalid if doesn't start with numbers
|
||||
Quickshell.execDetached(["notify-send", Translation.tr("Superpaste"), Translation.tr("Usage: <tt>%1superpaste NUM_OF_ENTRIES[i]</tt>\nSupply <tt>i</tt> when you want images\nExamples:\n<tt>%1superpaste 4i</tt> for the last 4 images\n<tt>%1superpaste 7</tt> for the last 7 entries").arg(Config.options.search.prefix.action), "-a", "Shell"]);
|
||||
return;
|
||||
}
|
||||
const syntaxMatch = /^(?:(\d+)(i)?)/.exec(args.trim());
|
||||
const count = syntaxMatch[1] ? parseInt(syntaxMatch[1]) : 1;
|
||||
const isImage = !!syntaxMatch[2];
|
||||
Cliphist.superpaste(count, isImage);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "todo",
|
||||
execute: args => {
|
||||
Todo.addTask(args);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "wallpaper",
|
||||
execute: () => {
|
||||
GlobalStates.wallpaperSelectorOpen = true;
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "wipeclipboard",
|
||||
execute: () => {
|
||||
Cliphist.wipe();
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
property string mathResult: ""
|
||||
property bool clipboardWorkSafetyActive: {
|
||||
const enabled = Config.options.workSafety.enable.clipboard;
|
||||
const sensitiveNetwork = (StringUtils.stringListContainsSubstring(Network.networkName.toLowerCase(), Config.options.workSafety.triggerCondition.networkNameKeywords))
|
||||
return enabled && sensitiveNetwork;
|
||||
}
|
||||
|
||||
function containsUnsafeLink(entry) {
|
||||
if (entry == undefined) return false;
|
||||
const unsafeKeywords = Config.options.workSafety.triggerCondition.linkKeywords;
|
||||
return StringUtils.stringListContainsSubstring(entry.toLowerCase(), unsafeKeywords);
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: nonAppResultsTimer
|
||||
interval: Config.options.search.nonAppResultDelay
|
||||
onTriggered: {
|
||||
let expr = root.query;
|
||||
if (expr.startsWith(Config.options.search.prefix.math)) {
|
||||
expr = expr.slice(Config.options.search.prefix.math.length);
|
||||
}
|
||||
mathProc.calculateExpression(expr);
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: mathProc
|
||||
property list<string> baseCommand: ["qalc", "-t"]
|
||||
function calculateExpression(expression) {
|
||||
mathProc.running = false;
|
||||
mathProc.command = baseCommand.concat(expression);
|
||||
mathProc.running = true;
|
||||
}
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
root.mathResult = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property list<var> results: {
|
||||
// Search results are handled here
|
||||
////////////////// Skip? //////////////////
|
||||
if (root.query == "")
|
||||
return [];
|
||||
|
||||
///////////// Special cases ///////////////
|
||||
if (root.query.startsWith(Config.options.search.prefix.clipboard)) {
|
||||
// Clipboard
|
||||
const searchString = StringUtils.cleanPrefix(root.query, Config.options.search.prefix.clipboard);
|
||||
return Cliphist.fuzzyQuery(searchString).map((entry, index, array) => {
|
||||
const mightBlurImage = Cliphist.entryIsImage(entry) && root.clipboardWorkSafetyActive;
|
||||
let shouldBlurImage = mightBlurImage;
|
||||
if (mightBlurImage) {
|
||||
shouldBlurImage = shouldBlurImage && (root.containsUnsafeLink(array[index - 1]) || root.containsUnsafeLink(array[index + 1]));
|
||||
}
|
||||
const type = `#${entry.match(/^\s*(\S+)/)?.[1] || ""}`;
|
||||
return {
|
||||
key: type,
|
||||
cliphistRawString: entry,
|
||||
name: StringUtils.cleanCliphistEntry(entry),
|
||||
clickActionName: "",
|
||||
type: type,
|
||||
execute: () => {
|
||||
Cliphist.copy(entry);
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
name: "Copy",
|
||||
materialIcon: "content_copy",
|
||||
execute: () => {
|
||||
Cliphist.copy(entry);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Delete",
|
||||
materialIcon: "delete",
|
||||
execute: () => {
|
||||
Cliphist.deleteEntry(entry);
|
||||
}
|
||||
}
|
||||
],
|
||||
blurImage: shouldBlurImage,
|
||||
blurImageText: Translation.tr("Work safety")
|
||||
};
|
||||
}).filter(Boolean);
|
||||
} else if (root.query.startsWith(Config.options.search.prefix.emojis)) {
|
||||
// Clipboard
|
||||
const searchString = StringUtils.cleanPrefix(root.query, Config.options.search.prefix.emojis);
|
||||
return Emojis.fuzzyQuery(searchString).map(entry => {
|
||||
const emoji = entry.match(/^\s*(\S+)/)?.[1] || "";
|
||||
return {
|
||||
key: emoji,
|
||||
cliphistRawString: entry,
|
||||
bigText: emoji,
|
||||
name: entry.replace(/^\s*\S+\s+/, ""),
|
||||
clickActionName: "",
|
||||
type: "Emoji",
|
||||
execute: () => {
|
||||
Quickshell.clipboardText = entry.match(/^\s*(\S+)/)?.[1];
|
||||
}
|
||||
};
|
||||
}).filter(Boolean);
|
||||
}
|
||||
|
||||
////////////////// Init ///////////////////
|
||||
nonAppResultsTimer.restart();
|
||||
const mathResultObject = {
|
||||
key: `Math result: ${root.mathResult}`,
|
||||
name: root.mathResult,
|
||||
clickActionName: Translation.tr("Copy"),
|
||||
type: Translation.tr("Math result"),
|
||||
fontType: "monospace",
|
||||
materialSymbol: 'calculate',
|
||||
execute: () => {
|
||||
Quickshell.clipboardText = root.mathResult;
|
||||
}
|
||||
};
|
||||
const appResultObjects = AppSearch.fuzzyQuery(StringUtils.cleanPrefix(root.query, Config.options.search.prefix.app)).map(entry => {
|
||||
entry.clickActionName = Translation.tr("Launch");
|
||||
entry.type = Translation.tr("App");
|
||||
entry.key = entry.execute;
|
||||
return entry;
|
||||
});
|
||||
const commandResultObject = {
|
||||
key: `cmd ${root.query}`,
|
||||
name: StringUtils.cleanPrefix(root.query, Config.options.search.prefix.shellCommand).replace("file://", ""),
|
||||
clickActionName: Translation.tr("Run"),
|
||||
type: Translation.tr("Run command"),
|
||||
fontType: "monospace",
|
||||
materialSymbol: 'terminal',
|
||||
execute: () => {
|
||||
let cleanedCommand = root.query.replace("file://", "");
|
||||
cleanedCommand = StringUtils.cleanPrefix(cleanedCommand, Config.options.search.prefix.shellCommand);
|
||||
if (cleanedCommand.startsWith(Config.options.search.prefix.shellCommand)) {
|
||||
cleanedCommand = cleanedCommand.slice(Config.options.search.prefix.shellCommand.length);
|
||||
}
|
||||
Quickshell.execDetached(["bash", "-c", searchingText.startsWith('sudo') ? `${Config.options.apps.terminal} fish -C '${cleanedCommand}'` : cleanedCommand]);
|
||||
}
|
||||
};
|
||||
const webSearchResultObject = {
|
||||
key: `website ${root.query}`,
|
||||
name: StringUtils.cleanPrefix(root.query, Config.options.search.prefix.webSearch),
|
||||
clickActionName: Translation.tr("Search"),
|
||||
type: Translation.tr("Search the web"),
|
||||
materialSymbol: 'travel_explore',
|
||||
execute: () => {
|
||||
let query = StringUtils.cleanPrefix(root.query, Config.options.search.prefix.webSearch);
|
||||
let url = Config.options.search.engineBaseUrl + query;
|
||||
for (let site of Config.options.search.excludedSites) {
|
||||
url += ` -site:${site}`;
|
||||
}
|
||||
Qt.openUrlExternally(url);
|
||||
}
|
||||
};
|
||||
const launcherActionObjects = root.searchActions.map(action => {
|
||||
const actionString = `${Config.options.search.prefix.action}${action.action}`;
|
||||
if (actionString.startsWith(root.query) || root.query.startsWith(actionString)) {
|
||||
return {
|
||||
key: `Action ${actionString}`,
|
||||
name: root.query.startsWith(actionString) ? root.query : actionString,
|
||||
clickActionName: Translation.tr("Run"),
|
||||
type: Translation.tr("Action"),
|
||||
materialSymbol: 'settings_suggest',
|
||||
execute: () => {
|
||||
action.execute(root.query.split(" ").slice(1).join(" "));
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}).filter(Boolean);
|
||||
|
||||
//////// Prioritized by prefix /////////
|
||||
let result = [];
|
||||
const startsWithNumber = /^\d/.test(root.query);
|
||||
const startsWithMathPrefix = root.query.startsWith(Config.options.search.prefix.math);
|
||||
const startsWithShellCommandPrefix = root.query.startsWith(Config.options.search.prefix.shellCommand);
|
||||
const startsWithWebSearchPrefix = root.query.startsWith(Config.options.search.prefix.webSearch);
|
||||
if (startsWithNumber || startsWithMathPrefix) {
|
||||
result.push(mathResultObject);
|
||||
} else if (startsWithShellCommandPrefix) {
|
||||
result.push(commandResultObject);
|
||||
} else if (startsWithWebSearchPrefix) {
|
||||
result.push(webSearchResultObject);
|
||||
}
|
||||
|
||||
//////////////// Apps //////////////////
|
||||
result = result.concat(appResultObjects);
|
||||
|
||||
////////// Launcher actions ////////////
|
||||
result = result.concat(launcherActionObjects);
|
||||
|
||||
/// Math result, command, web search ///
|
||||
if (Config.options.search.prefix.showDefaultActionsWithoutPrefix) {
|
||||
if (!startsWithShellCommandPrefix)
|
||||
result.push(commandResultObject);
|
||||
if (!startsWithNumber && !startsWithMathPrefix)
|
||||
result.push(mathResultObject);
|
||||
if (!startsWithWebSearchPrefix)
|
||||
result.push(webSearchResultObject);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import qs.modules.waffle.background
|
||||
import qs.modules.waffle.bar
|
||||
import qs.modules.waffle.notificationCenter
|
||||
import qs.modules.waffle.onScreenDisplay
|
||||
import qs.modules.waffle.startMenu
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Window
|
||||
@@ -77,11 +78,13 @@ ShellRoot {
|
||||
PanelLoader { identifier: "iiSidebarRight"; component: SidebarRight {} }
|
||||
PanelLoader { identifier: "iiVerticalBar"; extraCondition: Config.options.bar.vertical; component: VerticalBar {} }
|
||||
PanelLoader { identifier: "iiWallpaperSelector"; component: WallpaperSelector {} }
|
||||
|
||||
PanelLoader { identifier: "wActionCenter"; component: WaffleActionCenter {} }
|
||||
PanelLoader { identifier: "wBar"; component: WaffleBar {} }
|
||||
PanelLoader { identifier: "wBackground"; component: WaffleBackground {} }
|
||||
PanelLoader { identifier: "wNotificationCenter"; component: WaffleNotificationCenter {} }
|
||||
PanelLoader { identifier: "wOnScreenDisplay"; component: WaffleOSD {} }
|
||||
PanelLoader { identifier: "wStartMenu"; component: WaffleStartMenu {} }
|
||||
ReloadPopup {}
|
||||
|
||||
component PanelLoader: LazyLoader {
|
||||
@@ -94,7 +97,7 @@ ShellRoot {
|
||||
property list<string> families: ["ii", "waffle"]
|
||||
property var panelFamilies: ({
|
||||
"ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"],
|
||||
"waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "iiCheatsheet", "iiLock", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiWallpaperSelector"],
|
||||
"waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "wStartMenu", "iiCheatsheet", "iiLock", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiWallpaperSelector"],
|
||||
})
|
||||
function cyclePanelFamily() {
|
||||
const currentIndex = families.indexOf(Config.options.panelFamily)
|
||||
|
||||
@@ -191,6 +191,9 @@ Tips:
|
||||
- Used in Quickshell config.
|
||||
- `wlogout`
|
||||
- Used in Hyprland config.
|
||||
- `libqalculate`
|
||||
- Used in Quickshell config, providing math ability in searchbar.
|
||||
- Note that `qalc` is the needed executable. In Arch Linux [libqalculate](https://archlinux.org/packages/extra/x86_64/libqalculate) provides it, but in Fedora [qalculate](https://packages.fedoraproject.org/pkgs/libqalculate/qalculate/fedora-43.html#files) does and [libqalculate](https://packages.fedoraproject.org/pkgs/libqalculate/libqalculate/fedora-43.html#files) does not.
|
||||
|
||||
|
||||
# Actual packages
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
pkgname=illogical-impulse-widgets
|
||||
pkgver=1.0
|
||||
pkgrel=5
|
||||
pkgrel=6
|
||||
pkgdesc='Illogical Impulse Widget Dependencies'
|
||||
arch=(any)
|
||||
license=(None)
|
||||
@@ -14,4 +14,5 @@ depends=(
|
||||
songrec
|
||||
translate-shell
|
||||
wlogout
|
||||
libqalculate
|
||||
)
|
||||
|
||||
@@ -181,6 +181,7 @@ packages = [
|
||||
"hyprpicker",
|
||||
"songrec",
|
||||
"translate-shell",
|
||||
"qalculate",
|
||||
"wlogout"
|
||||
]
|
||||
|
||||
@@ -191,4 +192,5 @@ packages = [
|
||||
"plasma-systemmonitor",
|
||||
"unzip"
|
||||
]
|
||||
install_opts = ["--setopt=install_weak_deps=False"]
|
||||
install_opts = ["--setopt=install_weak_deps=False"]
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ RDEPEND="
|
||||
app-misc/songrec
|
||||
app-i18n/translate-shell
|
||||
gui-apps/wlogout
|
||||
sci-libs/libqalculate
|
||||
"
|
||||
##### CUSTOM EBUILDS
|
||||
# app-misc/songrec
|
||||
@@ -37,8 +37,38 @@ As [commented](https://github.com/end-4/dots-hyprland/issues/1061#issuecomment-3
|
||||
|
||||
See also [caelestia-dots/shell#668](https://github.com/caelestia-dots/shell/issues/668).
|
||||
|
||||
### NixGL
|
||||
On non-NixOS distros, packages installed via home-manager have problem accessing GPU, especially Hyprland because it requires GPU acceleration to launch. `nixGL` should be used to address the problem.
|
||||
### GPU
|
||||
On non-NixOS distros, packages installed via home-manager have problem accessing GPU, especially Hyprland because it requires GPU acceleration to launch.
|
||||
|
||||
~~`nixGL` should be used to address the problem.~~
|
||||
|
||||
Since home-manager 25.11, for non-NixOS just set the following:
|
||||
```nix
|
||||
targets.genericLinux.enable = true;
|
||||
```
|
||||
Then during building, home-manager will show a message to tell you running a command manually to configure GPU, like:
|
||||
```bash
|
||||
sudo /nix/store/<HASH>-non-nixos-gpu/bin/non-nixos-gpu-setup
|
||||
```
|
||||
It runs a bash script with following content:
|
||||
```
|
||||
#!/nix/store/<HASH>-bash-<VERSION>/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Install the systemd service file and ensure that the store path won't be
|
||||
# garbage-collected as long as it's installed.
|
||||
unit_path=/etc/systemd/system/non-nixos-gpu.service
|
||||
ln -sf /nix/store/<HASH>-non-nixos-gpu/resources/non-nixos-gpu.service "$unit_path"
|
||||
ln -sf "$unit_path" "/nix/var/nix"/gcroots/non-nixos-gpu.service
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable non-nixos-gpu.service
|
||||
systemctl restart non-nixos-gpu.service
|
||||
```
|
||||
_Note: it uses `systemctl`, maybe won't work for OpenRC..._
|
||||
|
||||
See [gpu-non-nixos](https://nix-community.github.io/home-manager/index.xhtml#sec-usage-gpu-non-nixos).
|
||||
|
||||
# Handling dot files
|
||||
## Status
|
||||
|
||||
@@ -3,23 +3,24 @@
|
||||
description = "illogical-impulse";
|
||||
|
||||
inputs = {
|
||||
# Qt 6.10 is not yet available from released version of nixpkgs.
|
||||
#nixpkgs.url = "nixpkgs/nixos-25.05";
|
||||
nixpkgs.url = "nixpkgs/nixos-unstable";
|
||||
nixpkgs.url = "nixpkgs/nixos-25.11";
|
||||
#nixpkgs.url = "nixpkgs/nixos-unstable";
|
||||
|
||||
home-manager = {
|
||||
#url = "github:nix-community/home-manager/release-25.05";
|
||||
url = "github:nix-community/home-manager/master";
|
||||
url = "github:nix-community/home-manager/release-25.11";
|
||||
#url = "github:nix-community/home-manager/master";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
nixgl.url = "github:nix-community/nixGL";
|
||||
#nixgl.url = "github:nix-community/nixGL";
|
||||
quickshell = {
|
||||
url = "github:quickshell-mirror/quickshell/db1777c20b936a86528c1095cbcb1ebd92801402";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { nixpkgs, home-manager, nixgl, quickshell, ... }:
|
||||
outputs = { nixpkgs, home-manager,
|
||||
#nixgl,
|
||||
quickshell, ... }:
|
||||
let
|
||||
home_attrs = rec {
|
||||
username = import ./username.nix;
|
||||
@@ -36,7 +37,9 @@
|
||||
homeConfigurations = {
|
||||
illogical_impulse = home-manager.lib.homeManagerConfiguration {
|
||||
inherit pkgs;
|
||||
extraSpecialArgs = { inherit home_attrs nixgl quickshell; };
|
||||
extraSpecialArgs = { inherit home_attrs
|
||||
#nixgl
|
||||
quickshell; };
|
||||
modules = [
|
||||
./home.nix
|
||||
];
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
{ config, lib, pkgs, nixgl, quickshell, home_attrs, ... }:
|
||||
{ config, lib, pkgs,
|
||||
#nixgl,
|
||||
quickshell, home_attrs, ... }:
|
||||
{
|
||||
programs.home-manager.enable = true;
|
||||
nixGL.packages = nixgl.packages;
|
||||
nixGL.defaultWrapper = "mesa";
|
||||
|
||||
# Necessary for non-NixOS to handle GPU (since home-manager version 25.11)
|
||||
targets.genericLinux.enable = true;
|
||||
#nixGL.packages = nixgl.packages;
|
||||
#nixGL.defaultWrapper = "mesa";
|
||||
|
||||
xdg.portal = {
|
||||
enable = true;
|
||||
@@ -27,7 +32,8 @@
|
||||
systemd.enable = false; plugins = []; settings = {}; extraConfig = "";
|
||||
enable = true;
|
||||
## Use NixGL
|
||||
package = config.lib.nixGL.wrap pkgs.hyprland;
|
||||
#package = config.lib.nixGL.wrap pkgs.hyprland;
|
||||
package = pkgs.hyprland;
|
||||
};
|
||||
|
||||
home = {
|
||||
@@ -167,6 +173,7 @@
|
||||
songrec #songrec
|
||||
translate-shell #translate-shell
|
||||
wlogout #wlogout
|
||||
libqalculate #libqalculate
|
||||
|
||||
]
|
||||
++ [
|
||||
@@ -174,7 +181,9 @@
|
||||
|
||||
### illogical-impulse-quickshell-git
|
||||
#(config.lib.nixGL.wrap quickshell.packages.x86_64-linux.default)
|
||||
(import ./quickshell.nix { inherit pkgs quickshell; nixGLWrap = config.lib.nixGL.wrap; })
|
||||
(import ./quickshell.nix { inherit pkgs quickshell;
|
||||
#nixGLWrap = config.lib.nixGL.wrap;
|
||||
})
|
||||
];
|
||||
}//home_attrs;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
{ pkgs, quickshell, nixGLWrap, ... }:
|
||||
{ pkgs, quickshell,
|
||||
#nixGLWrap,
|
||||
... }:
|
||||
let
|
||||
qs = nixGLWrap quickshell.packages.x86_64-linux.default;
|
||||
#qs = nixGLWrap quickshell.packages.x86_64-linux.default;
|
||||
qs = quickshell.packages.x86_64-linux.default;
|
||||
in pkgs.stdenv.mkDerivation {
|
||||
name = "illogical-impulse-quickshell-wrapper";
|
||||
meta = with pkgs.lib; {
|
||||
description = "Quickshell wrapped with NixGL + bundled Qt deps for home-manager usage";
|
||||
#description = "Quickshell wrapped with NixGL + bundled Qt deps for home-manager usage";
|
||||
description = "Quickshell bundled Qt deps for home-manager usage";
|
||||
license = licenses.gpl3Only;
|
||||
};
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ function install_home-manager(){
|
||||
try source $HOME/.nix-profile/etc/profile.d/hm-session-vars.sh
|
||||
command -v $cmd && return
|
||||
|
||||
x nix-channel --add https://nixos.org/channels/nixos-25.05 nixpkgs-home
|
||||
x nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.05.tar.gz home-manager
|
||||
x nix-channel --add https://nixos.org/channels/nixos-25.11 nixpkgs-home
|
||||
x nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz home-manager
|
||||
x nix-channel --update
|
||||
x env NIX_PATH="nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs-home" nix-shell '<home-manager>' -A install
|
||||
|
||||
@@ -56,6 +56,7 @@ function hm_deps(){
|
||||
x home-manager switch --flake .#illogical_impulse \
|
||||
--extra-experimental-features nix-command \
|
||||
--extra-experimental-features flakes
|
||||
x sudo /nix/store/*-non-nixos-gpu/bin/non-nixos-gpu-setup
|
||||
cd $REPO_ROOT
|
||||
x git rm -f "${SETUP_USERNAME_NIXFILE}"
|
||||
}
|
||||
|
||||