Reworked toggle buttons and added power menu

This commit is contained in:
2025-02-07 22:09:12 -08:00
parent 0fea2069f1
commit ffc8737756
16 changed files with 281 additions and 109 deletions

32
assets/hyprland.svg Normal file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 515.34 673.26">
<defs>
<style>
.cls-1 {
mix-blend-mode: difference;
}
.cls-2 {
isolation: isolate;
}
.cls-3 {
fill: url(#linear-gradient);
}
</style>
<linearGradient id="linear-gradient" x1="8.93" y1="572.38" x2="572.68" y2="102.08" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#00a2f8" />
<stop offset="1" stop-color="#00e5cf" />
</linearGradient>
</defs>
<g class="cls-2">
<g id="Layer_2" data-name="Layer 2">
<g id="Layer_1-2" data-name="Layer 1">
<g class="cls-1">
<path class="cls-3"
d="m288.53,0c1.99,2.11,3.26,3.13,4.14,4.42,15.97,23.63,31.7,47.44,47.91,70.91,9.33,13.51,19.26,26.61,29.22,39.67,9.63,12.65,19.8,24.88,29.44,37.53,11.15,14.63,22.45,29.18,32.81,44.36,13.27,19.45,26.64,38.94,38.12,59.44,9.76,17.43,17.56,36.05,25.02,54.64,5.28,13.16,8.82,27.06,12.6,40.78,1.75,6.36,2.24,13.07,3.26,19.62,1.26,8.02,3.4,16.04,3.53,24.08.35,20.94,2.17,41.95-1.48,62.8-4.02,22.99-10.75,45-20.76,66.23-10.12,21.45-22.38,41.26-37.39,59.59-13.6,16.61-29.57,30.33-46.84,42.91-12.68,9.23-26.09,17.07-40.36,23.3-12.84,5.6-26.07,10.09-39.69,13.89-30.75,8.56-61.93,10.44-93.33,8.23-18.93-1.33-38.08-3.65-56.11-10.46-14.82-5.6-29.75-11.13-43.92-18.13-11.19-5.52-21.91-12.44-31.73-20.15-12.88-10.11-25.52-20.81-36.67-32.74-9.99-10.68-18.64-22.87-26.4-35.31-8.18-13.13-15.39-27.01-21.58-41.2-6.69-15.32-11.01-31.45-14.53-47.97-5.48-25.71-3.71-51.44-2.59-77.09.64-14.73,4.53-29.47,8.26-43.86,3.93-15.18,8.68-30.26,14.44-44.84,5.77-14.6,12.47-28.96,20.14-42.65,9.63-17.18,20.25-33.85,31.2-50.23,9.94-14.88,20.68-29.24,31.47-43.52,8.69-11.5,18.17-22.41,26.97-33.83,8.9-11.55,17.46-23.36,26.07-35.13,9.11-12.46,18.29-24.87,27.09-37.55,11.16-16.07,21.91-32.43,32.97-48.57,1.58-2.31,3.88-4.14,5.84-6.19.39.22.78.44,1.18.66.08,1.77.23,3.54.23,5.31.01,26.33.15,52.66-.17,78.99-.05,3.86-1.62,8.15-3.72,11.46-8.5,13.45-17.19,26.8-26.38,39.79-8.71,12.31-18.12,24.13-27.22,36.16-7.5,9.91-14.97,19.83-22.52,29.7-5.24,6.85-10.74,13.5-15.86,20.44-7.16,9.72-14.35,19.45-21.03,29.5-8.06,12.12-15.99,24.36-23.23,36.97-5.18,9.02-9.26,18.69-13.59,28.17-2.4,5.26-4.61,10.64-6.36,16.14-3.1,9.76-5.58,19.71-8.68,29.47-8.72,27.42-6.87,55.63-4.92,83.5.99,14.15,6.11,28.15,10.4,41.89,6.01,19.24,16.32,36.3,27.95,52.74,7.94,11.23,16.95,21.38,27.14,30.36,8.39,7.38,17.5,14.17,27.07,19.92,10.89,6.54,22.23,12.77,34.12,17.07,12.69,4.59,26.1,7.99,39.48,9.68,15.93,2.01,32.16,1.58,48.25,2.34,14.94.7,29.43-2.29,43.93-5.14,18.41-3.62,35.23-11.56,51.58-20.26,19.55-10.4,35.98-25.13,50.37-41.73,14.71-16.97,27.06-36.05,34.92-57,8.29-22.1,15.2-44.97,14.15-69.26-.57-13.13.15-26.34-1.06-39.39-.89-9.61-3.62-19.11-6.16-28.5-2.98-11.03-6.03-22.1-10.16-32.73-4.11-10.59-9.36-20.75-14.52-30.9-4.57-8.99-9.32-17.92-14.66-26.46-6.5-10.39-13.38-20.59-20.68-30.43-11.05-14.9-22.74-29.32-33.91-44.12-13.08-17.33-26.13-34.68-38.77-52.33-10.91-15.22-21.31-30.81-31.71-46.39-1.67-2.5-3-5.79-3.03-8.72-.23-28.49-.15-56.98-.13-85.47,0-.95.24-1.91.58-4.44Z" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

7
assets/lock-symbolic.svg Normal file
View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 1.3 KiB

7
assets/logout.svg Normal file
View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12,7.33a1,1,0,0,0,1-1V5.78l6-1.5V7.22L14.7,8.3a1,1,0,0,0,.24,2l.24,0L20.24,9l.07,0,.19-.09.15-.1a.93.93,0,0,0,.13-.15.78.78,0,0,0,.1-.15.55.55,0,0,0,.06-.18.65.65,0,0,0,0-.19A.24.24,0,0,0,21,8V3a1,1,0,0,0-1.24-1l-8,2A1,1,0,0,0,11,5V6.33A1,1,0,0,0,12,7.33Zm9.71,13-9-9h0l-9-9A1,1,0,0,0,2.29,3.71L11,12.41v2.94A3.45,3.45,0,0,0,9.5,15,3.5,3.5,0,1,0,13,18.5V14.41l7.29,7.3a1,1,0,0,0,1.42,0A1,1,0,0,0,21.71,20.29ZM9.5,20A1.5,1.5,0,1,1,11,18.5,1.5,1.5,0,0,1,9.5,20Z"/></svg>

Before

Width:  |  Height:  |  Size: 701 B

7
assets/reboot.svg Normal file
View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 808 B

7
assets/shutdown.svg Normal file
View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 1.0 KiB

7
assets/suspend.svg Normal file
View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 960 B

View File

@@ -21,10 +21,10 @@ button {
color: $text-1; color: $text-1;
padding: 0; padding: 0;
> box, > overlay > box { > box, > overlay > box, > label {
transition: ease-out 0.2s; transition: ease-out 0.2s;
border-radius: 12px; border-radius: 12px;
padding: 0 6px 0 6px; padding: 0 6px;
margin: 2px 6px 4px 6px; margin: 2px 6px 4px 6px;
color: $text-1; color: $text-1;
} }
@@ -38,11 +38,11 @@ button {
&:hover { &:hover {
color: transparent; color: transparent;
> box, > overlay > box { > box, > overlay > box, > label {
background: $background-2; background: $background-2;
} }
&.selected { &.selected {
> box, > overlay > box { > box, > overlay > box, > label {
background: $highlight-1s; background: $highlight-1s;
} }
} }
@@ -118,7 +118,7 @@ button {
> box { > box {
background: $background-3; background: $background-3;
border-radius: 10px; border-radius: 10px;
box-shadow: 0 0 10px 4px black; box-shadow: 0 0 16px 4px black;
padding: 10px; padding: 10px;
margin: 48px 40px 40px 12px; margin: 48px 40px 40px 12px;
} }
@@ -157,13 +157,19 @@ button {
} }
.toggleButton { .toggleButton {
> box {
padding: 0;
}
label {
color: white;
}
:not(.toggleIndicator) {
background: none;
}
&.bt { &.bt {
icon { icon {
margin-right: 8px; margin-right: 8px;
} }
box {
background: none;
}
label { label {
margin-top: 2px; margin-top: 2px;
margin-right: 60px; margin-right: 60px;
@@ -172,20 +178,11 @@ button {
&:hover .toggleIndicator { &:hover .toggleIndicator {
box-shadow: 0 0 6px 0px $highlight-3; box-shadow: 0 0 6px 0px $highlight-3;
} }
> overlay {
margin: 0;
padding: 6px 0px 6px 0px;
> label { > label {
color: $text-1; color: $text-1;
font-size: 16px; font-size: 16px;
margin: 2px; margin: 2px;
} }
> .active {
margin: 4px 12px 4px 0;
min-width: 32px;
background: $highlight-3;
}
}
} }
.scroller { .scroller {
@@ -302,9 +299,14 @@ button {
min-height: 6px; min-height: 6px;
min-width: 24px; min-width: 24px;
padding: 0; padding: 0;
margin: 4px 16px 4px 0; margin: 4px 4px 4px 0;
border: 2px solid $highlight-3; border: 2px solid $highlight-3;
border-radius: 8px; border-radius: 8px;
&.active {
margin: 4px 0px 4px 0;
min-width: 32px;
background: $highlight-3;
}
} }
@keyframes notifIn { @keyframes notifIn {
@@ -315,7 +317,7 @@ button {
@keyframes glowIn { @keyframes glowIn {
from { from {
background: white; background: white;
box-shadow: 0 0 10px 4px white; box-shadow: 0 0 16px 4px white;
} }
} }
@@ -325,15 +327,19 @@ button {
background: $background-3; background: $background-3;
border-radius: 10px; border-radius: 10px;
padding: 8px; padding: 8px;
box-shadow: 0 0 10px 4px black; box-shadow: 0 0 16px 4px black;
min-width: 300px; min-width: 300px;
margin: 12px 12px 40px 40px; margin: 12px 12px 40px 40px;
} }
.notifIcon { .notifIcon {
min-width: 64px; min-width: 48px;
min-height: 64px; min-height: 48px;
margin: 8px; margin: 8px;
background-size: contain; background-size: contain;
border-radius: 10px; border-radius: 10px;
} }
.panelNotifBox {
min-width: 400px;
}

View File

@@ -9,6 +9,7 @@ import client from "./client"
import player from "./player" import player from "./player"
import bluetooth from "./bluetooth" import bluetooth from "./bluetooth"
import notifs from "./notif" import notifs from "./notif"
import power from "./power"
const time = Variable("").poll(1000, "date +'%a %b %d · %H:%M'") const time = Variable("").poll(1000, "date +'%a %b %d · %H:%M'")
@@ -21,11 +22,13 @@ export default function Bar(monitor: Hyprland.Monitor) {
monitor={monitor.id} monitor={monitor.id}
exclusivity={Astal.Exclusivity.IGNORE} exclusivity={Astal.Exclusivity.IGNORE}
anchor={TOP | LEFT | RIGHT} anchor={TOP | LEFT | RIGHT}
heightRequest={36}
layer={Astal.Layer.TOP} layer={Astal.Layer.TOP}
application={App}> application={App}>
<centerbox> <eventbox
onHover={self => self.css="box-shadow: 0 0 16px 4px black;"}
><centerbox heightRequest={36}>
<box> <box>
{power()}
{battery()} {battery()}
{volume()} {volume()}
{brightness()} {brightness()}
@@ -43,6 +46,6 @@ export default function Bar(monitor: Hyprland.Monitor) {
</box></button> </box></button>
{notifs()} {notifs()}
</box> </box>
</centerbox> </centerbox></eventbox>
</window> </window>
} }

View File

@@ -19,17 +19,19 @@ function profileButton(label: string, profile: string) {
return <button className="toggleButton" onClicked={(self) => { return <button className="toggleButton" onClicked={(self) => {
powerProfiles.activeProfile = profile powerProfiles.activeProfile = profile
}}> }}>
<overlay overlay={new Widget.Box({ <box halign={Gtk.Align.FILL}>
halign: Gtk.Align.END, <label halign={Gtk.Align.START} hexpand>{label}</label>
valign: Gtk.Align.CENTER, <box
className: bind(powerProfiles, "activeProfile").as((p) => halign={Gtk.Align.END}
valign={Gtk.Align.CENTER}
className={bind(powerProfiles, "activeProfile").as((p) =>
(p === profile) (p === profile)
? "toggleIndicator active" ? "toggleIndicator active"
: "toggleIndicator inactive" : "toggleIndicator inactive"
) )
})}> }
<label halign={Gtk.Align.START}>{label}</label> />
</overlay> </box>
</button> </button>
} }
@@ -63,47 +65,40 @@ function BattWindow() {
/> />
</overlay> </overlay>
<box vertical={true} spacing={10}> <box vertical={true} spacing={10}>
<overlay overlay={new Widget.Box({ <box className="info" vertical>
halign: Gtk.Align.CENTER, <label
valign: Gtk.Align.CENTER, css="font-size: 16px;"
vertical: true, vexpand
children: [ valign={Gtk.Align.END}>
new Widget.Label({ {bind(batt, "energyRate").as(w => `${w}W`)}
className: "bigText", </label>
label: bind(batt, "energyRate").as((w) => `${w}W`), <label
}), vexpand
new Widget.Label({ valign={Gtk.Align.START}>
className: "smallText", {bind(batt, "charging").as(c =>
label: bind(batt, "charging").as( c ? "Charging" : "Discharging"
(c) => c ? "Charging" : "Discharging" )}
), </label>
}), </box>
] <box className="info" vertical>
})}> <label
<box className="info" /> css="font-size: 16px;"
</overlay> vexpand
<overlay overlay={new Widget.Box({ valign={Gtk.Align.END}>
halign: Gtk.Align.CENTER, {mergeBindings([charging, toFull, toEmpty]).as(
valign: Gtk.Align.CENTER,
vertical: true,
children: [
new Widget.Label({
className: "status",
label: mergeBindings([charging, toFull, toEmpty]).as(
(b) => { (b) => {
let s = (b[0] ? b[1] : b[2]) let s = (b[0] ? b[1] : b[2])
return `${Math.floor(s/3600)}H ${Math.floor((s%3600)/60)}M` return `${Math.floor(s/3600)}H ${Math.floor((s%3600)/60)}M`
} }
), )
}), }
new Widget.Label({ </label>
className: "title", <label
label: charging.as(c => c ? "To full" : "To empty"), vexpand
}), valign={Gtk.Align.START}>
] {charging.as(c => c ? "To full" : "To empty")}
})}> </label>
<box className="info" /> </box>
</overlay>
</box> </box>
</box> </box>
<box <box

View File

@@ -13,18 +13,13 @@ function bluetoothItem(device: Bluetooth.Device) {
onClicked={() => { onClicked={() => {
execAsync(["bluetoothctl", device.connected ? "disconnect" : "connect", device.address]).then(out => console.log(out)).catch(out => console.log(out)) execAsync(["bluetoothctl", device.connected ? "disconnect" : "connect", device.address]).then(out => console.log(out)).catch(out => console.log(out))
}}> }}>
<overlay overlay={new Widget.Box({
className: bind(device, "connected").as(c =>
"toggleIndicator ".concat(c ? "active" : "inactive")
),
halign: Gtk.Align.END,
valign: Gtk.Align.CENTER,
})}>
<box> <box>
<box hexpand>
<icon icon={device.icon ?? "bluetooth"} css="font-size: 32px;" /> <icon icon={device.icon ?? "bluetooth"} css="font-size: 32px;" />
<label valign={Gtk.Align.CENTER}>{device.alias ?? device.name}</label> <label valign={Gtk.Align.CENTER}>{device.alias ?? device.name}</label>
</box> </box>
</overlay> <box className={bind(device, "connected").as(c => "toggleIndicator ".concat(c ? "active" : "inactive"))} halign={Gtk.Align.END} valign={Gtk.Align.CENTER}/>
</box>
</button> </button>
} }

View File

@@ -68,9 +68,12 @@ function BrightWindow() {
.then((out) => (console.log(out))) .then((out) => (console.log(out)))
.catch((out) => (console.log(out))) .catch((out) => (console.log(out)))
}} }}
><overlay overlay={toggleIndicator}> >
<label halign={Gtk.Align.START}>Night Light</label> <box>
</overlay></button> <label hexpand halign={Gtk.Align.START}>Night Light</label>
{toggleIndicator}
</box>
</button>
</box> </box>
</window> </window>
} }

View File

@@ -23,11 +23,11 @@ function NewClient(client: Hyprland.Client) {
} }
let b = <box halign={Gtk.Align.END} className="clientLabel" visible={true}> let b = <box halign={Gtk.Align.END} className="clientLabel" visible={true}>
<icon <icon
icon={(appsClass) ? appsClass.iconName : "archlinux"} icon={(appsClass) ? appsClass.iconName : "hyprland"}
css="font-size: 24px; margin-right: 4px;" css="font-size: 24px; margin-right: 4px;"
/> />
<label css="font-family: comfortaa; font-size: 14px;">{ <label css="font-family: comfortaa; font-size: 14px;">{
(appsClass) ? appsClass.name : "Hummingbird" (appsClass) ? appsClass.name : "Hyprland"
}</label> }</label>
</box> </box>
return b return b

View File

@@ -4,16 +4,16 @@ import Notif from "gi://AstalNotifd"
import Pango from "gi://Pango?version=1.0" import Pango from "gi://Pango?version=1.0"
const notifs = Notif.get_default() const notifs = Notif.get_default()
const { TOP, RIGHT } = Astal.WindowAnchor const { TOP, RIGHT, BOTTOM } = Astal.WindowAnchor
const notifPlaceholder = "/home/protoshark/.config/ags/assets/notif.svg" const notifPlaceholder = "/home/protoshark/.config/ags/assets/notif.svg"
let notifWindow: Widget.Window let notifWindow: Widget.Window
function NewNotif(notif: Notif.Notification) {
function NewNotif(notif: Notif.Notification, inPanel: boolean = true) {
return <box return <box
className="notifBox" className={inPanel ? "notifBox" : "panelNotifBox"}
halign={Gtk.Align.END} halign={Gtk.Align.END}
valign={Gtk.Align.START} > valign={Gtk.Align.START}
<box
spacing={8}> spacing={8}>
<box <box
halign={Gtk.Align.CENTER} halign={Gtk.Align.CENTER}
@@ -21,7 +21,11 @@ function NewNotif(notif: Notif.Notification) {
className="notifIcon" className="notifIcon"
css={`background-image: url("${notif.image ?? notifPlaceholder}")`} css={`background-image: url("${notif.image ?? notifPlaceholder}")`}
/> />
<box vertical={true} valign={Gtk.Align.CENTER} spacing={6}> <box
vertical
valign={Gtk.Align.CENTER}
spacing={6}
hexpand>
<label <label
halign={Gtk.Align.START} halign={Gtk.Align.START}
css="font-size: 16px;" css="font-size: 16px;"
@@ -39,7 +43,45 @@ function NewNotif(notif: Notif.Notification) {
{notif.body.substring(0, 88)} {notif.body.substring(0, 88)}
</label> </label>
</box> </box>
</box></box> <box vertical valign={Gtk.Align.CENTER}>
{notif.actions.map(action => <button onClicked={() => {
notif.invoke(action.id)
}}>
<box><icon icon={action.label.toLowerCase()} css="margin: 4px -2px;"/></box>
</button>)}
</box>
</box>
}
function NotifPanel() {
return <window
anchor={ TOP | RIGHT | BOTTOM }
marginTop={36}
namespace="notifpanel" >
<box vertical={true}>
<box>
<button
hexpand
heightRequest={36}
onClicked={() => {
for (let n of notifs.notifications) {
n.dismiss()
}
}}>Clear notifications</button>
<button
hexpand
heightRequest={36}
onClicked={() => {
notifs.dontDisturb = !notifs.dontDisturb
}}>Do not disturb</button>
</box>
<scrollable widthRequest={416} vexpand>
<box vertical={true}>
{notifs.notifications.map(n => NewNotif(n, false))}
</box>
</scrollable>
</box>
</window>
} }
function notify(notif: Notif.Notification) { function notify(notif: Notif.Notification) {
@@ -59,6 +101,7 @@ function notify(notif: Notif.Notification) {
notifWindow = <window notifWindow = <window
anchor={ TOP | RIGHT } anchor={ TOP | RIGHT }
marginTop={36} marginTop={36}
layer={Astal.Layer.OVERLAY}
css="background: transparent;" css="background: transparent;"
namespace="notification"> namespace="notification">
<overlay overlay={thisNotif}> <overlay overlay={thisNotif}>
@@ -93,7 +136,14 @@ function notifCount() {
export default function notifWidget() { export default function notifWidget() {
return <button return <button
onClicked={() => {}} onClicked={() => {
if (notifWindow) {
notifWindow.destroy()
notifWindow = null
} else {
notifWindow = NotifPanel()
}
}}
setup={(self) => self.hook(notifs, "notified", (_, id) => { setup={(self) => self.hook(notifs, "notified", (_, id) => {
notify(notifs.get_notification(id)) notify(notifs.get_notification(id))
})}> })}>

View File

@@ -44,16 +44,6 @@ function cover(player: Mpris.Player) {
return coverOverlay return coverOverlay
} }
function wrap(str: string) {
if (str.length > 40) {
str = str.substring(0, 40)
}
if (str.length > 20) {
return str.substring(0, 20) + "\n" + str.substring(20)
}
return str
}
function playerBox(player: Mpris.Player) { function playerBox(player: Mpris.Player) {
return <box return <box
vertical={true} vertical={true}
@@ -92,12 +82,16 @@ function playerBox(player: Mpris.Player) {
new Widget.Label({ new Widget.Label({
className: "playerTitle", className: "playerTitle",
justify: Gtk.Justification.CENTER, justify: Gtk.Justification.CENTER,
label: bind(player, "title").as(str => wrap(str)) wrap: true,
width_chars: 20,
label: bind(player, "title").as(str => str.substring(0, 60))
}), }),
new Widget.Label({ new Widget.Label({
className: "playerArtist", className: "playerArtist",
justify: Gtk.Justification.CENTER, justify: Gtk.Justification.CENTER,
label: bind(player, "artist").as(str => wrap(str)) wrap: true,
width_chars: 20,
label: bind(player, "artist").as(str => str.substring(0, 60))
}) })
] ]
}) })

61
widget/power.tsx Normal file
View File

@@ -0,0 +1,61 @@
import { Astal } from "astal/gtk3"
import { popup } from "./popup"
import { execAsync } from "astal"
const { TOP, LEFT } = Astal.WindowAnchor
function PowerWindow() {
return <window
className="popupWindow"
anchor={ TOP | LEFT }
namespace="lazerpopup">
<box vertical css="padding: 6px 0;">
{[
["Lock", "bash -c 'pgrep -x hyprlock || hyprlock &'" ],
["Suspend", "/home/protoshark/.config/scripts/lock.sh" ],
["Logout", "hyprctl dispatch exit" ],
["Shutdown", "systemctl poweroff" ],
["Reboot", "systemctl reboot" ],
].map(action => <button onClicked={() => {
execAsync(action[1])
.then(out => print(out))
.catch(out => print(out))
popup.window.destroy()
popup.window = null
popup.state = ""
}}>
<box hexpand css="padding: 4px 8px 4px 0;">
<icon icon={action[0].toLowerCase()} css="margin: 0 6px;"/>
<label>{action[0]}</label>
</box>
</button>)}
</box>
</window>
}
export default function power() {
return <button onClicked={(self) => {
if (popup.state !== "power") {
if (popup.window !== null) {
popup.window.destroy()
popup.window = null
}
popup.window = PowerWindow();
popup.state = "power"
self.toggleClassName("selected", true)
self.hook(popup.window, "destroy", () => {
self.toggleClassName("selected", false)
popup.window = null
popup.state = ""
})
} else {
popup.window.destroy()
popup.window = null
popup.state = ""
}
}}>
<box>
<icon icon="archlinux" />
</box>
</button>
}