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 |
50
style.scss
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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))
|
||||||
})}>
|
})}>
|
||||||
|
|||||||
@@ -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
@@ -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>
|
||||||
|
}
|
||||||