Reworked toggle buttons and added power menu
32
assets/hyprland.svg
Normal 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
@@ -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
@@ -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 |
@@ -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
@@ -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
@@ -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
@@ -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 |
58
style.scss
@@ -21,10 +21,10 @@ button {
|
||||
color: $text-1;
|
||||
padding: 0;
|
||||
|
||||
> box, > overlay > box {
|
||||
> box, > overlay > box, > label {
|
||||
transition: ease-out 0.2s;
|
||||
border-radius: 12px;
|
||||
padding: 0 6px 0 6px;
|
||||
padding: 0 6px;
|
||||
margin: 2px 6px 4px 6px;
|
||||
color: $text-1;
|
||||
}
|
||||
@@ -38,11 +38,11 @@ button {
|
||||
|
||||
&:hover {
|
||||
color: transparent;
|
||||
> box, > overlay > box {
|
||||
> box, > overlay > box, > label {
|
||||
background: $background-2;
|
||||
}
|
||||
&.selected {
|
||||
> box, > overlay > box {
|
||||
> box, > overlay > box, > label {
|
||||
background: $highlight-1s;
|
||||
}
|
||||
}
|
||||
@@ -118,7 +118,7 @@ button {
|
||||
> box {
|
||||
background: $background-3;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 10px 4px black;
|
||||
box-shadow: 0 0 16px 4px black;
|
||||
padding: 10px;
|
||||
margin: 48px 40px 40px 12px;
|
||||
}
|
||||
@@ -157,13 +157,19 @@ button {
|
||||
}
|
||||
|
||||
.toggleButton {
|
||||
> box {
|
||||
padding: 0;
|
||||
}
|
||||
label {
|
||||
color: white;
|
||||
}
|
||||
:not(.toggleIndicator) {
|
||||
background: none;
|
||||
}
|
||||
&.bt {
|
||||
icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
box {
|
||||
background: none;
|
||||
}
|
||||
label {
|
||||
margin-top: 2px;
|
||||
margin-right: 60px;
|
||||
@@ -172,19 +178,10 @@ button {
|
||||
&:hover .toggleIndicator {
|
||||
box-shadow: 0 0 6px 0px $highlight-3;
|
||||
}
|
||||
> overlay {
|
||||
margin: 0;
|
||||
padding: 6px 0px 6px 0px;
|
||||
> label {
|
||||
color: $text-1;
|
||||
font-size: 16px;
|
||||
margin: 2px;
|
||||
}
|
||||
> .active {
|
||||
margin: 4px 12px 4px 0;
|
||||
min-width: 32px;
|
||||
background: $highlight-3;
|
||||
}
|
||||
> label {
|
||||
color: $text-1;
|
||||
font-size: 16px;
|
||||
margin: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,9 +299,14 @@ button {
|
||||
min-height: 6px;
|
||||
min-width: 24px;
|
||||
padding: 0;
|
||||
margin: 4px 16px 4px 0;
|
||||
margin: 4px 4px 4px 0;
|
||||
border: 2px solid $highlight-3;
|
||||
border-radius: 8px;
|
||||
&.active {
|
||||
margin: 4px 0px 4px 0;
|
||||
min-width: 32px;
|
||||
background: $highlight-3;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes notifIn {
|
||||
@@ -315,7 +317,7 @@ button {
|
||||
@keyframes glowIn {
|
||||
from {
|
||||
background: white;
|
||||
box-shadow: 0 0 10px 4px white;
|
||||
box-shadow: 0 0 16px 4px white;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,15 +327,19 @@ button {
|
||||
background: $background-3;
|
||||
border-radius: 10px;
|
||||
padding: 8px;
|
||||
box-shadow: 0 0 10px 4px black;
|
||||
box-shadow: 0 0 16px 4px black;
|
||||
min-width: 300px;
|
||||
margin: 12px 12px 40px 40px;
|
||||
}
|
||||
|
||||
.notifIcon {
|
||||
min-width: 64px;
|
||||
min-height: 64px;
|
||||
min-width: 48px;
|
||||
min-height: 48px;
|
||||
margin: 8px;
|
||||
background-size: contain;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.panelNotifBox {
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import client from "./client"
|
||||
import player from "./player"
|
||||
import bluetooth from "./bluetooth"
|
||||
import notifs from "./notif"
|
||||
import power from "./power"
|
||||
|
||||
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}
|
||||
exclusivity={Astal.Exclusivity.IGNORE}
|
||||
anchor={TOP | LEFT | RIGHT}
|
||||
heightRequest={36}
|
||||
layer={Astal.Layer.TOP}
|
||||
application={App}>
|
||||
<centerbox>
|
||||
<eventbox
|
||||
onHover={self => self.css="box-shadow: 0 0 16px 4px black;"}
|
||||
><centerbox heightRequest={36}>
|
||||
<box>
|
||||
{power()}
|
||||
{battery()}
|
||||
{volume()}
|
||||
{brightness()}
|
||||
@@ -43,6 +46,6 @@ export default function Bar(monitor: Hyprland.Monitor) {
|
||||
</box></button>
|
||||
{notifs()}
|
||||
</box>
|
||||
</centerbox>
|
||||
</centerbox></eventbox>
|
||||
</window>
|
||||
}
|
||||
|
||||
@@ -19,17 +19,19 @@ function profileButton(label: string, profile: string) {
|
||||
return <button className="toggleButton" onClicked={(self) => {
|
||||
powerProfiles.activeProfile = profile
|
||||
}}>
|
||||
<overlay overlay={new Widget.Box({
|
||||
halign: Gtk.Align.END,
|
||||
valign: Gtk.Align.CENTER,
|
||||
className: bind(powerProfiles, "activeProfile").as((p) =>
|
||||
<box halign={Gtk.Align.FILL}>
|
||||
<label halign={Gtk.Align.START} hexpand>{label}</label>
|
||||
<box
|
||||
halign={Gtk.Align.END}
|
||||
valign={Gtk.Align.CENTER}
|
||||
className={bind(powerProfiles, "activeProfile").as((p) =>
|
||||
(p === profile)
|
||||
? "toggleIndicator active"
|
||||
: "toggleIndicator inactive"
|
||||
)
|
||||
})}>
|
||||
<label halign={Gtk.Align.START}>{label}</label>
|
||||
</overlay>
|
||||
}
|
||||
/>
|
||||
</box>
|
||||
</button>
|
||||
}
|
||||
|
||||
@@ -63,47 +65,40 @@ function BattWindow() {
|
||||
/>
|
||||
</overlay>
|
||||
<box vertical={true} spacing={10}>
|
||||
<overlay overlay={new Widget.Box({
|
||||
halign: Gtk.Align.CENTER,
|
||||
valign: Gtk.Align.CENTER,
|
||||
vertical: true,
|
||||
children: [
|
||||
new Widget.Label({
|
||||
className: "bigText",
|
||||
label: bind(batt, "energyRate").as((w) => `${w}W`),
|
||||
}),
|
||||
new Widget.Label({
|
||||
className: "smallText",
|
||||
label: bind(batt, "charging").as(
|
||||
(c) => c ? "Charging" : "Discharging"
|
||||
),
|
||||
}),
|
||||
]
|
||||
})}>
|
||||
<box className="info" />
|
||||
</overlay>
|
||||
<overlay overlay={new Widget.Box({
|
||||
halign: Gtk.Align.CENTER,
|
||||
valign: Gtk.Align.CENTER,
|
||||
vertical: true,
|
||||
children: [
|
||||
new Widget.Label({
|
||||
className: "status",
|
||||
label: mergeBindings([charging, toFull, toEmpty]).as(
|
||||
<box className="info" vertical>
|
||||
<label
|
||||
css="font-size: 16px;"
|
||||
vexpand
|
||||
valign={Gtk.Align.END}>
|
||||
{bind(batt, "energyRate").as(w => `${w}W`)}
|
||||
</label>
|
||||
<label
|
||||
vexpand
|
||||
valign={Gtk.Align.START}>
|
||||
{bind(batt, "charging").as(c =>
|
||||
c ? "Charging" : "Discharging"
|
||||
)}
|
||||
</label>
|
||||
</box>
|
||||
<box className="info" vertical>
|
||||
<label
|
||||
css="font-size: 16px;"
|
||||
vexpand
|
||||
valign={Gtk.Align.END}>
|
||||
{mergeBindings([charging, toFull, toEmpty]).as(
|
||||
(b) => {
|
||||
let s = (b[0] ? b[1] : b[2])
|
||||
return `${Math.floor(s/3600)}H ${Math.floor((s%3600)/60)}M`
|
||||
}
|
||||
),
|
||||
}),
|
||||
new Widget.Label({
|
||||
className: "title",
|
||||
label: charging.as(c => c ? "To full" : "To empty"),
|
||||
}),
|
||||
]
|
||||
})}>
|
||||
<box className="info" />
|
||||
</overlay>
|
||||
)
|
||||
}
|
||||
</label>
|
||||
<label
|
||||
vexpand
|
||||
valign={Gtk.Align.START}>
|
||||
{charging.as(c => c ? "To full" : "To empty")}
|
||||
</label>
|
||||
</box>
|
||||
</box>
|
||||
</box>
|
||||
<box
|
||||
|
||||
@@ -13,18 +13,13 @@ function bluetoothItem(device: Bluetooth.Device) {
|
||||
onClicked={() => {
|
||||
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;" />
|
||||
<label valign={Gtk.Align.CENTER}>{device.alias ?? device.name}</label>
|
||||
</box>
|
||||
</overlay>
|
||||
<box className={bind(device, "connected").as(c => "toggleIndicator ".concat(c ? "active" : "inactive"))} halign={Gtk.Align.END} valign={Gtk.Align.CENTER}/>
|
||||
</box>
|
||||
</button>
|
||||
}
|
||||
|
||||
|
||||
@@ -68,9 +68,12 @@ function BrightWindow() {
|
||||
.then((out) => (console.log(out)))
|
||||
.catch((out) => (console.log(out)))
|
||||
}}
|
||||
><overlay overlay={toggleIndicator}>
|
||||
<label halign={Gtk.Align.START}>Night Light</label>
|
||||
</overlay></button>
|
||||
>
|
||||
<box>
|
||||
<label hexpand halign={Gtk.Align.START}>Night Light</label>
|
||||
{toggleIndicator}
|
||||
</box>
|
||||
</button>
|
||||
</box>
|
||||
</window>
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ function NewClient(client: Hyprland.Client) {
|
||||
}
|
||||
let b = <box halign={Gtk.Align.END} className="clientLabel" visible={true}>
|
||||
<icon
|
||||
icon={(appsClass) ? appsClass.iconName : "archlinux"}
|
||||
icon={(appsClass) ? appsClass.iconName : "hyprland"}
|
||||
css="font-size: 24px; margin-right: 4px;"
|
||||
/>
|
||||
<label css="font-family: comfortaa; font-size: 14px;">{
|
||||
(appsClass) ? appsClass.name : "Hummingbird"
|
||||
(appsClass) ? appsClass.name : "Hyprland"
|
||||
}</label>
|
||||
</box>
|
||||
return b
|
||||
|
||||
@@ -4,16 +4,16 @@ import Notif from "gi://AstalNotifd"
|
||||
import Pango from "gi://Pango?version=1.0"
|
||||
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"
|
||||
let notifWindow: Widget.Window
|
||||
|
||||
function NewNotif(notif: Notif.Notification) {
|
||||
|
||||
function NewNotif(notif: Notif.Notification, inPanel: boolean = true) {
|
||||
return <box
|
||||
className="notifBox"
|
||||
className={inPanel ? "notifBox" : "panelNotifBox"}
|
||||
halign={Gtk.Align.END}
|
||||
valign={Gtk.Align.START} >
|
||||
<box
|
||||
valign={Gtk.Align.START}
|
||||
spacing={8}>
|
||||
<box
|
||||
halign={Gtk.Align.CENTER}
|
||||
@@ -21,7 +21,11 @@ function NewNotif(notif: Notif.Notification) {
|
||||
className="notifIcon"
|
||||
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
|
||||
halign={Gtk.Align.START}
|
||||
css="font-size: 16px;"
|
||||
@@ -39,7 +43,45 @@ function NewNotif(notif: Notif.Notification) {
|
||||
{notif.body.substring(0, 88)}
|
||||
</label>
|
||||
</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) {
|
||||
@@ -59,6 +101,7 @@ function notify(notif: Notif.Notification) {
|
||||
notifWindow = <window
|
||||
anchor={ TOP | RIGHT }
|
||||
marginTop={36}
|
||||
layer={Astal.Layer.OVERLAY}
|
||||
css="background: transparent;"
|
||||
namespace="notification">
|
||||
<overlay overlay={thisNotif}>
|
||||
@@ -93,7 +136,14 @@ function notifCount() {
|
||||
|
||||
export default function notifWidget() {
|
||||
return <button
|
||||
onClicked={() => {}}
|
||||
onClicked={() => {
|
||||
if (notifWindow) {
|
||||
notifWindow.destroy()
|
||||
notifWindow = null
|
||||
} else {
|
||||
notifWindow = NotifPanel()
|
||||
}
|
||||
}}
|
||||
setup={(self) => self.hook(notifs, "notified", (_, id) => {
|
||||
notify(notifs.get_notification(id))
|
||||
})}>
|
||||
|
||||
@@ -44,16 +44,6 @@ function cover(player: Mpris.Player) {
|
||||
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) {
|
||||
return <box
|
||||
vertical={true}
|
||||
@@ -92,12 +82,16 @@ function playerBox(player: Mpris.Player) {
|
||||
new Widget.Label({
|
||||
className: "playerTitle",
|
||||
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({
|
||||
className: "playerArtist",
|
||||
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
@@ -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>
|
||||
}
|
||||