Add battery and notifications to QuickSettings popup
This commit is contained in:
parent
56fe96de47
commit
84607b7ac1
|
|
@ -91,8 +91,7 @@ $module-bg: transparentize($base02, 0.4);
|
|||
color: $base00;
|
||||
}
|
||||
|
||||
.ws:hover,
|
||||
.battery:hover {
|
||||
.ws:hover {
|
||||
background: transparentize($base05, 0.88);
|
||||
}
|
||||
|
||||
|
|
@ -254,14 +253,23 @@ $module-bg: transparentize($base02, 0.4);
|
|||
background: transparentize($base05, 0.88);
|
||||
}
|
||||
|
||||
.battery-percent {
|
||||
font-size: 1.6em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.battery-level {
|
||||
font-size: 0.85em;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.battery-section {
|
||||
margin-top: 10px;
|
||||
border-top: 1px solid $base02;
|
||||
padding-top: 8px;
|
||||
|
||||
icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.battery-percent {
|
||||
font-weight: bold;
|
||||
margin: 0 6px;
|
||||
}
|
||||
|
||||
.battery-status {
|
||||
|
|
@ -269,6 +277,49 @@ $module-bg: transparentize($base02, 0.4);
|
|||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.notif-section {
|
||||
margin-top: 10px;
|
||||
border-top: 1px solid $base02;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.notif-toggle {
|
||||
padding: 4px 6px;
|
||||
border-radius: 6px;
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: transparentize($base05, 0.88);
|
||||
}
|
||||
}
|
||||
|
||||
.notif-clear {
|
||||
padding: 4px 10px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85em;
|
||||
|
||||
&:hover {
|
||||
background: transparentize($base05, 0.88);
|
||||
}
|
||||
}
|
||||
|
||||
.notif-empty {
|
||||
font-size: 0.85em;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.quicksettings .notif-count {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.notif-section .notif {
|
||||
background: $base02;
|
||||
}
|
||||
|
||||
.notifications {
|
||||
.notif {
|
||||
background: $base01;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { App, Astal, Gdk, Gtk } from "astal/gtk3"
|
|||
import Workspaces from "./Workspaces"
|
||||
import Logo from "./Logo"
|
||||
import Clock from "./Clock"
|
||||
import { BatteryWidget } from "./Battery"
|
||||
import QuickSettings from "./QuickSettings"
|
||||
|
||||
const RADIUS = 12
|
||||
|
|
@ -54,16 +53,11 @@ function Corner({ side }: { side: "left" | "right" }) {
|
|||
|
||||
export default function Bar(gdkmonitor: Gdk.Monitor) {
|
||||
const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
|
||||
const battery = BatteryWidget(gdkmonitor)
|
||||
const quicksettings = QuickSettings(gdkmonitor)
|
||||
|
||||
const right: Array<JSX.Element> = []
|
||||
if (battery.button) right.push(battery.button)
|
||||
right.push(quicksettings.button)
|
||||
const right: Array<JSX.Element> = [quicksettings.button]
|
||||
|
||||
const popups: Array<JSX.Element> = []
|
||||
if (battery.popup) popups.push(battery.popup)
|
||||
popups.push(quicksettings.popup)
|
||||
const popups: Array<JSX.Element> = [quicksettings.popup]
|
||||
|
||||
return [
|
||||
(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import Gtk from "gi://Gtk?version=3.0"
|
||||
import AstalBattery from "gi://AstalBattery"
|
||||
import { Variable, bind } from "astal"
|
||||
import Dropdown from "./Dropdown"
|
||||
import { type Binding, Variable, bind } from "astal"
|
||||
|
||||
const battery = AstalBattery.get_default()
|
||||
|
||||
|
|
@ -31,28 +31,20 @@ const status = Variable.derive(
|
|||
},
|
||||
)
|
||||
|
||||
export function BatteryWidget(gdkmonitor: Gdk.Monitor) {
|
||||
if (!battery.isBattery) return { button: null, popup: null }
|
||||
export const batteryIcon: Binding<string> | null = battery.isBattery
|
||||
? bind(battery, "icon-name")
|
||||
: null
|
||||
|
||||
const open = Variable(false)
|
||||
export const batteryPercent: Binding<string> | null = battery.isBattery
|
||||
? bind(battery, "percentage").as((p) => `${Math.round(p * 100)}%`)
|
||||
: null
|
||||
|
||||
const button = (
|
||||
<button
|
||||
className="battery"
|
||||
onClicked={() => open.set(!open.get())}
|
||||
>
|
||||
<box>
|
||||
<icon icon={bind(battery, "icon-name")} />
|
||||
<label
|
||||
className="battery-level"
|
||||
label={bind(battery, "percentage").as((p) => `${Math.round(p * 100)}%`)}
|
||||
/>
|
||||
</box>
|
||||
</button>
|
||||
)
|
||||
export function BatterySection() {
|
||||
if (!battery.isBattery) return <box />
|
||||
|
||||
const popup = (
|
||||
<Dropdown gdkmonitor={gdkmonitor} target={button} open={open} width={180}>
|
||||
return (
|
||||
<box className="battery-section">
|
||||
<icon icon={bind(battery, "icon-name")} />
|
||||
<label
|
||||
className="battery-percent"
|
||||
label={bind(battery, "percentage").as((p) => `${Math.round(p * 100)}%`)}
|
||||
|
|
@ -61,9 +53,9 @@ export function BatteryWidget(gdkmonitor: Gdk.Monitor) {
|
|||
className="battery-status"
|
||||
label={status()}
|
||||
visible={status().as((text) => text !== "")}
|
||||
hexpand
|
||||
halign={Gtk.Align.START}
|
||||
/>
|
||||
</Dropdown>
|
||||
</box>
|
||||
)
|
||||
|
||||
return { button, popup }
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ function formatTime(n: Notifd.Notification) {
|
|||
return GLib.DateTime.new_from_unix_local(n.time).format("%H:%M")!
|
||||
}
|
||||
|
||||
function NotificationCard(n: Notifd.Notification) {
|
||||
export function NotificationCard(n: Notifd.Notification) {
|
||||
const critical = n.urgency === Notifd.Urgency.CRITICAL
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,10 +1,17 @@
|
|||
import Gtk from "gi://Gtk?version=3.0"
|
||||
import AstalWp from "gi://AstalWp"
|
||||
import Notifd from "gi://AstalNotifd"
|
||||
import { execAsync, Variable, bind } from "astal"
|
||||
import Dropdown from "./Dropdown"
|
||||
import { wifiIcon, WifiSection } from "./Wifi"
|
||||
import { batteryIcon, batteryPercent, BatterySection } from "./Battery"
|
||||
import { NotificationCard } from "./Notifications"
|
||||
|
||||
const speaker = AstalWp.get_default().audio.default_speaker!
|
||||
const mic = AstalWp.get_default().audio.default_microphone
|
||||
const notifd = Notifd.get_default()
|
||||
|
||||
const notifCount = bind(notifd, "notifications").as((ns) => ns.length)
|
||||
|
||||
const speakerIcon = Variable.derive(
|
||||
[bind(speaker, "volume"), bind(speaker, "mute")],
|
||||
|
|
@ -34,6 +41,11 @@ const actions = [
|
|||
|
||||
export default function QuickSettings(gdkmonitor: Gdk.Monitor) {
|
||||
const open = Variable(false)
|
||||
const notifOpen = Variable(false)
|
||||
|
||||
open.subscribe((v) => {
|
||||
if (!v) notifOpen.set(false)
|
||||
})
|
||||
|
||||
const button = (
|
||||
<button
|
||||
|
|
@ -48,9 +60,23 @@ export default function QuickSettings(gdkmonitor: Gdk.Monitor) {
|
|||
}}
|
||||
>
|
||||
<box spacing={6}>
|
||||
<box className="notif-indicator" spacing={3}>
|
||||
<icon icon="preferences-system-notifications-symbolic" />
|
||||
<label
|
||||
className="notif-count"
|
||||
label={notifCount.as((n) => `${n}`)}
|
||||
visible={notifCount.as((n) => n > 0)}
|
||||
/>
|
||||
</box>
|
||||
{wifiIcon && <icon icon={wifiIcon} />}
|
||||
<icon icon={speakerIcon()} />
|
||||
{micIcon && <icon icon={micIcon()} />}
|
||||
{wifiIcon && <icon icon={wifiIcon} />}
|
||||
{batteryIcon && batteryPercent && (
|
||||
<box spacing={3}>
|
||||
<icon icon={batteryIcon} />
|
||||
<label className="battery-level" label={batteryPercent} />
|
||||
</box>
|
||||
)}
|
||||
</box>
|
||||
</button>
|
||||
)
|
||||
|
|
@ -98,6 +124,51 @@ export default function QuickSettings(gdkmonitor: Gdk.Monitor) {
|
|||
</box>
|
||||
)}
|
||||
<WifiSection open={open} />
|
||||
<BatterySection />
|
||||
<box className="notif-section" vertical spacing={6}>
|
||||
<box className="notif-header-row" spacing={6}>
|
||||
<button
|
||||
className="notif-toggle"
|
||||
hexpand
|
||||
halign={Gtk.Align.START}
|
||||
onClicked={() => notifOpen.set(!notifOpen.get())}
|
||||
>
|
||||
<box spacing={6}>
|
||||
<icon icon="preferences-system-notifications-symbolic" />
|
||||
<label label="Notifications" />
|
||||
<icon
|
||||
icon={notifOpen().as((v) =>
|
||||
v ? "pan-down-symbolic" : "pan-end-symbolic",
|
||||
)}
|
||||
/>
|
||||
</box>
|
||||
</button>
|
||||
<button
|
||||
className="notif-clear"
|
||||
onClicked={() => [...notifd.notifications].forEach((n) => n.dismiss())}
|
||||
>
|
||||
<label label="Clear" />
|
||||
</button>
|
||||
</box>
|
||||
<revealer
|
||||
transitionType={Gtk.RevealerTransitionType.SLIDE_DOWN}
|
||||
transitionDuration={180}
|
||||
revealChild={bind(notifOpen)}
|
||||
>
|
||||
<box className="notifications" vertical>
|
||||
<label
|
||||
className="notif-empty"
|
||||
label="no notifications"
|
||||
visible={notifCount.as((n) => n === 0)}
|
||||
/>
|
||||
{bind(notifd, "notifications").as((ns) =>
|
||||
[...ns]
|
||||
.sort((a, b) => b.time - a.time)
|
||||
.map((n) => NotificationCard(n)),
|
||||
)}
|
||||
</box>
|
||||
</revealer>
|
||||
</box>
|
||||
</Dropdown>
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue