179 lines
4.4 KiB
JavaScript
179 lines
4.4 KiB
JavaScript
|
const battery = await Service.import('battery')
|
||
|
const audio = await Service.import('audio')
|
||
|
const hyprland = await Service.import('hyprland')
|
||
|
const mpris = await Service.import('mpris')
|
||
|
const notifications = await Service.import('notifications')
|
||
|
const systemtray = await Service.import('systemtray')
|
||
|
|
||
|
/// WORKSPACES ///
|
||
|
|
||
|
const Workspaces = () => Widget.EventBox({
|
||
|
onScrollDown: () => hyprland.messageAsync(`dispatch workspace -1`),
|
||
|
onScrollUp: () => hyprland.messageAsync(`dispatch workspace +1`),
|
||
|
|
||
|
child: Widget.Box({
|
||
|
spacing: 8,
|
||
|
|
||
|
//?? Increase length if workspaces > 10
|
||
|
children: Array.from({ length: 10 }, (_, i) => i + 1).map(i => Widget.Button({
|
||
|
onClicked: () => hyprland.messageAsync(`dispatch workspace ${i}`),
|
||
|
|
||
|
attribute: i,
|
||
|
label: `${i}`,
|
||
|
})),
|
||
|
|
||
|
// Initial button visibility
|
||
|
setup: self => self.hook(hyprland, () => self.children.forEach(btn => {
|
||
|
btn.visible = hyprland.workspaces.some(ws => ws.id === btn.attribute)
|
||
|
})),
|
||
|
}),
|
||
|
})
|
||
|
|
||
|
/// CLOCK ///
|
||
|
|
||
|
const Clock = () => Widget.Label({
|
||
|
class_name: 'clock',
|
||
|
|
||
|
setup: self => self.poll(1000, self =>
|
||
|
Utils.execAsync(['date', '+%a %b %d %I:%M %p'])
|
||
|
.then(date => self.label = date)),
|
||
|
})
|
||
|
|
||
|
/// NOTIFICATIONS ///
|
||
|
|
||
|
const Notification = () => Widget.Box({
|
||
|
class_name: 'notification',
|
||
|
visible: notifications.bind('popups').transform(p => p.length > 0),
|
||
|
children: [
|
||
|
Widget.Icon({
|
||
|
icon: 'preferences-system-notifications-symbolic',
|
||
|
}),
|
||
|
Widget.Label({
|
||
|
label: notifications.bind('popups').transform(p => p[0]?.summary || ''),
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
/// PLAYER ///
|
||
|
|
||
|
const Media = () => Widget.Button({
|
||
|
class_name: 'media',
|
||
|
on_primary_click: () => mpris.getPlayer('')?.playPause(),
|
||
|
on_scroll_up: () => mpris.getPlayer('')?.next(),
|
||
|
on_scroll_down: () => mpris.getPlayer('')?.previous(),
|
||
|
child: Widget.Label('-').hook(mpris, self => {
|
||
|
if (mpris.players[0]) {
|
||
|
const { track_artists, track_title } = mpris.players[0]
|
||
|
self.label = `${track_artists.join(', ')} - ${track_title}`
|
||
|
} else {
|
||
|
self.label = 'Nothing is playing'
|
||
|
}
|
||
|
}, 'player-changed'),
|
||
|
})
|
||
|
|
||
|
/// VOLUME ///
|
||
|
console.log(audio.speaker)
|
||
|
const Volume = () => Widget.Button({
|
||
|
on_clicked: () => audio.speaker.is_muted = !audio.speaker.is_muted,
|
||
|
|
||
|
child: Widget.Icon().hook(audio.speaker, self => {
|
||
|
const icon = [
|
||
|
[101, 'overamplified'],
|
||
|
[67, 'high'],
|
||
|
[34, 'medium'],
|
||
|
[0, 'low'],
|
||
|
].find(([threshold]) => threshold <= audio.speaker.volume * 100)?.[1]
|
||
|
|
||
|
self.icon = `audio-volume-${icon}-symbolic`
|
||
|
self.tooltip_text = `Volume ${Math.floor(audio.speaker.volume * 100)}%`
|
||
|
}),
|
||
|
})
|
||
|
|
||
|
/// BATTERY ///
|
||
|
|
||
|
const Battery = () => Widget.Box({
|
||
|
spacing: 4,
|
||
|
class_name: battery.bind('charging').transform(c => c ? 'charging' : ''),
|
||
|
visible: battery.bind('available'),
|
||
|
|
||
|
children: [
|
||
|
// Battery icon
|
||
|
Widget.Icon({
|
||
|
icon: battery.bind('percent').transform(p => `battery-level-${Math.floor(p / 10) * 10}-symbolic`),
|
||
|
}),
|
||
|
|
||
|
// Battery discharge wattage
|
||
|
Widget.Label({
|
||
|
label: battery.bind('energy-rate').transform(e => `${Math.round(e)}W`),
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
/// TRAY ///
|
||
|
|
||
|
const SysTray = () => Widget.Box({
|
||
|
children: systemtray.bind('items').transform(items => {
|
||
|
return items.map(item => Widget.Button({
|
||
|
child: Widget.Icon({ binds: [['icon', item, 'icon']] }),
|
||
|
on_primary_click: (_, event) => item.activate(event),
|
||
|
on_secondary_click: (_, event) => item.openMenu(event),
|
||
|
binds: [['tooltip-markup', item, 'tooltip-markup']],
|
||
|
}))
|
||
|
}),
|
||
|
})
|
||
|
|
||
|
/// LAYOUT ///
|
||
|
|
||
|
const Left = () => Widget.Box({
|
||
|
spacing: 8,
|
||
|
children: [
|
||
|
Workspaces(),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
const Center = () => Widget.Box({
|
||
|
spacing: 8,
|
||
|
children: [
|
||
|
Clock(),
|
||
|
Notification(),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
const Right = () => Widget.Box({
|
||
|
hpack: 'end',
|
||
|
spacing: 8,
|
||
|
children: [
|
||
|
Media(),
|
||
|
SysTray(),
|
||
|
Volume(),
|
||
|
Battery(),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
const Bar = (monitor = 0) => Widget.Window({
|
||
|
monitor,
|
||
|
name: `bar${monitor}`,
|
||
|
class_name: 'bar',
|
||
|
anchor: ['top', 'left', 'right'],
|
||
|
exclusivity: 'exclusive',
|
||
|
|
||
|
child: Widget.EventBox({
|
||
|
on_scroll_up: () => audio['speaker'].volume = audio['speaker'].volume + 1,
|
||
|
on_scroll_down: () => audio['speaker'].volume = audio['speaker'].volume + 1,
|
||
|
|
||
|
child: Widget.CenterBox({
|
||
|
spacing: 8,
|
||
|
start_widget: Left(),
|
||
|
center_widget: Center(),
|
||
|
end_widget: Right(),
|
||
|
}),
|
||
|
})
|
||
|
})
|
||
|
|
||
|
/// EXPORTS ///
|
||
|
|
||
|
export default {
|
||
|
style: './style.css',
|
||
|
windows: [Bar()],
|
||
|
}
|