From e966ba0cb64212346df7bbe646d8baa5ffacfe31 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sat, 6 Jul 2024 17:14:50 +0700 Subject: [PATCH] Update ags bar to master + create ags service --- flake.lock | 21 - flake.nix | 5 - modules/common/ags/config.js | 66 +-- modules/common/ags/default.nix | 51 +- modules/common/ags/layouts/bar.js | 84 ++-- modules/common/ags/modules/audio.js | 516 +++++++++----------- modules/common/ags/modules/battery.js | 89 +--- modules/common/ags/modules/bluetooth.js | 186 ++++--- modules/common/ags/modules/clock.js | 25 +- modules/common/ags/modules/network.js | 241 ++++----- modules/common/ags/modules/notifications.js | 498 +++++++++---------- modules/common/ags/shell.nix | 6 + modules/common/{ => ags}/tsconfig.json | 4 +- modules/common/ags/types | 1 + modules/dwl/default.nix | 1 - modules/river/default.nix | 2 - 16 files changed, 817 insertions(+), 979 deletions(-) create mode 100644 modules/common/ags/shell.nix rename modules/common/{ => ags}/tsconfig.json (93%) create mode 120000 modules/common/ags/types diff --git a/flake.lock b/flake.lock index beb51da..af0ea98 100644 --- a/flake.lock +++ b/flake.lock @@ -1,25 +1,5 @@ { "nodes": { - "ags": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1700329027, - "narHash": "sha256-zZy1Obdtek9bHbssEjl6EXBY3pFWYyT4Um/oEruG2us=", - "owner": "zoriya", - "repo": "ags", - "rev": "90eab170202f233e1600154da0beffda2dc9ef7c", - "type": "github" - }, - "original": { - "owner": "zoriya", - "repo": "ags", - "type": "github" - } - }, "dwl-source": { "flake": false, "locked": { @@ -540,7 +520,6 @@ }, "root": { "inputs": { - "ags": "ags", "dwl-source": "dwl-source", "flood": "flood", "ghostty": "ghostty", diff --git a/flake.nix b/flake.nix index ad4175c..06b828f 100644 --- a/flake.nix +++ b/flake.nix @@ -29,10 +29,6 @@ url = "github:djpohly/dwl?ref=755fcae2afbed51f38c167bdc56a5437cda8137a"; flake = false; }; - ags = { - url = "github:zoriya/ags"; - inputs.nixpkgs.follows = "nixpkgs"; - }; flood = { url = "github:zoriya/flood"; flake = false; @@ -43,7 +39,6 @@ self, home-manager, neovim-nightly, - ags, nixpkgs, ghostty, dwl-source, diff --git a/modules/common/ags/config.js b/modules/common/ags/config.js index defa4c7..5708801 100644 --- a/modules/common/ags/config.js +++ b/modules/common/ags/config.js @@ -1,51 +1,31 @@ import { Bar } from "./layouts/bar.js"; -import { Notifications } from "./layouts/notifications.js"; -import { OSD } from "./layouts/osd.js"; -import { Powermenu } from "./layouts/powermenu.js"; -import { Quicksettings } from "./layouts/quicksettings.js"; +// import { Notifications } from "./layouts/notifications.js"; +// import { OSD } from "./layouts/osd.js"; +// import { Powermenu } from "./layouts/powermenu.js"; +// import { Quicksettings } from "./layouts/quicksettings.js"; -import App from 'resource:///com/github/Aylur/ags/app.js' -import Audio from 'resource:///com/github/Aylur/ags/service/audio.js' -import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js' -import { timeout } from 'resource:///com/github/Aylur/ags/utils.js'; -const Gdk = imports.gi.Gdk; -const { Display } = imports.gi.Gdk; +import Gtk from "gi://Gtk?version=3.0"; +import Gdk from "gi://Gdk"; -globalThis.audio = Audio; -globalThis.mpris = Mpris; +/** + * @param {(monitor: number) => Gtk.Window} widget + */ +export function forMonitors(widget) { + const n = Gdk.Display.get_default()?.get_n_monitors() || 1; + return Array.from({ length: n }, (_, i) => i).flatMap(widget); +} -const config = { +App.config({ closeWindowDelay: { quicksettings: 300, notifications: 300, }, - style: App.configDir + "/style.css", - monitorFactory: (mon) => [Bar(mon, `${mon.geometry.x},${mon.geometry.y}`)], - windows: [Quicksettings(), Notifications(), OSD(), Powermenu()], -}; - -const registerMonitors = (config) => { - const display = Display.get_default(); - display.connect("monitor-added", (_, monitor) => { - // We wait for the geometry to be initialized by gdk. - timeout(500, () => { - const newWindows = config.monitorFactory(monitor); - for (const window of newWindows) App.addWindow(window); - }); - }); - display.connect("monitor-removed", (_, monitor) => { - for (const [name, win] of App.windows) { - if (win.monitor == monitor) ags.App.removeWindow(name); - } - }); - - for (let i = 0; i < display.get_n_monitors(); i++) { - const mon = display.get_monitor(i); - // console.log(mon, Gdk.Display.get_default()?.get_default_screen().get_monitor_plug_name(mon)); - config.monitorFactory(mon); - } - - return config; -}; - -export default registerMonitors(config); + style: `${App.configDir}/style.css`, + windows: [ + ...forMonitors(Bar), + // Quicksettings(), + // Notifications(), + // OSD(), + // Powermenu(), + ], +}); diff --git a/modules/common/ags/default.nix b/modules/common/ags/default.nix index eb7e5ac..09c63e0 100644 --- a/modules/common/ags/default.nix +++ b/modules/common/ags/default.nix @@ -1,30 +1,37 @@ {pkgs, ...}: let - covercolors = pkgs.stdenv.mkDerivation { - name = "covercolors"; - dontUnpack = true; - propagatedBuildInputs = [ - (pkgs.python3.withPackages (pyPkgs: - with pyPkgs; [ - material-color-utilities - pillow - ])) - ]; - installPhase = "install -Dm755 ${./covercolors.py} $out/bin/covercolors"; - }; + # covercolors = pkgs.stdenv.mkDerivation { + # name = "covercolors"; + # dontUnpack = true; + # propagatedBuildInputs = [ + # (pkgs.python3.withPackages (pyPkgs: + # with pyPkgs; [ + # material-color-utilities + # pillow + # ])) + # ]; + # installPhase = "install -Dm755 ${./covercolors.py} $out/bin/covercolors"; + # }; + systemdTarget = "graphical-session.target"; in { - home.packages = with pkgs; [ - # TODO: Remove this - covercolors - alsa-utils - sassc - brightnessctl - pavucontrol - glib - ]; + systemd.user.services.ags = { + Unit = { + Description = " A customizable and extensible shell "; + PartOf = systemdTarget; + Requires = systemdTarget; + After = systemdTarget; + }; + + Service = { + Type = "simple"; + ExecStart = "${pkgs.ags}/bin/ags"; + Restart = "always"; + }; + + Install = {WantedBy = [systemdTarget];}; + }; xdg.configFile."ags" = { source = ./.; recursive = true; }; - } diff --git a/modules/common/ags/layouts/bar.js b/modules/common/ags/layouts/bar.js index b742d64..e6d8b0c 100644 --- a/modules/common/ags/layouts/bar.js +++ b/modules/common/ags/layouts/bar.js @@ -1,39 +1,38 @@ import { Clock } from "../modules/clock.js"; -import * as dwl from "../modules/dwl.js"; import * as audio from "../modules/audio.js"; import * as network from "../modules/network.js"; import * as bluetooth from "../modules/bluetooth.js"; import * as battery from "../modules/battery.js"; import * as notifications from "../modules/notifications.js"; -import App from 'resource:///com/github/Aylur/ags/app.js'; -import { Window, CenterBox, Box, Button } from 'resource:///com/github/Aylur/ags/widget.js'; - -export const Bar = (mon, monId) => - Window({ - name: `bar${monId}`, +/** + *@param {number} monitor + */ +export const Bar = (monitor) => + Widget.Window({ + monitor, + name: `bar${monitor}`, className: "transparent", - exclusive: true, + exclusivity: "exclusive", anchor: ["top", "left", "right"], layer: "bottom", - gdkmonitor: mon, - child: CenterBox({ - startWidget: Box({ + child: Widget.CenterBox({ + startWidget: Widget.Box({ children: [ - dwl.Tags({ - mon: monId, - labels: ["一", "二", "三", "四", "五", "六", "七", "八", "九"], - }), - dwl.Layout({ - mon: monId, - }), - dwl.ClientLabel({ mon: monId }), + // dwl.Tags({ + // mon: monId, + // labels: ["一", "二", "三", "四", "五", "六", "七", "八", "九"], + // }), + // dwl.Layout({ + // mon: monId, + // }), + // dwl.ClientLabel({ mon: monId }), ], }), - centerWidget: Box({ + centerWidget: Widget.Box({ hpack: "center", children: [ - Button({ + Widget.Button({ css: "min-width: 200px;", onClicked: () => App.toggleWindow("notifications"), child: notifications.Indicator({ @@ -43,39 +42,38 @@ export const Bar = (mon, monId) => }), ], }), - endWidget: Box({ + endWidget: Widget.Box({ hpack: "end", children: [ - // TODO: - // ScreenShare() - // Webcam - // ScreenRecord(), - // ColorPicker(), - Button({ + Widget.Button({ onClicked: () => App.toggleWindow("quicksettings"), className: "module quicksettings", - connections: [ - [ - App, - (btn, win, visible) => { - btn.toggleClassName("active", win === "quicksettings" && visible); - }, - ], - ], - child: Box({ + child: Widget.Box({ children: [ - // audio.MicUseIndicator({ className: "qs-icon" }), - audio.MicrophoneMuteIndicator({ unmuted: null, className: "qs-item" }), - notifications.DNDIndicator({ noisy: null, className: "qs-item" }), + audio.MicrophoneIndicator({ + className: "qs-item", + }), + notifications.DNDIndicator({ + className: "qs-item", + }), network.Indicator({ className: "qs-item" }), - audio.SpeakerIndicator({ className: "qs-item" }), - bluetooth.Indicator({ disabled: null, className: "qs-item" }), + audio.VolumeIndicator({ className: "qs-item" }), + bluetooth.Indicator({ + hideIfDisabled: true, + className: "qs-item", + }), battery.Indicator({ className: "qs-item" }), ], }), + }).hook(App, (self, win, visible) => { + self.toggleClassName("active", win === "quicksettings" && visible); }), Clock({ format: "%a %d %b", className: "module bold" }), - Clock({ format: "%H:%M", className: "module accent bold", css: "margin-right: 0px" }), + Clock({ + format: "%H:%M", + className: "module accent bold", + css: "margin-right: 0px", + }), ], }), }), diff --git a/modules/common/ags/modules/audio.js b/modules/common/ags/modules/audio.js index 595ed50..565600c 100644 --- a/modules/common/ags/modules/audio.js +++ b/modules/common/ags/modules/audio.js @@ -1,296 +1,252 @@ -import { Separator, FontIcon, addElipsis } from "../misc.js"; -import { ArrowToggle, opened } from "../services/quicksettings.js"; +// import { Separator, FontIcon, addElipsis } from "../misc.js"; +// import { ArrowToggle, opened } from "../services/quicksettings.js"; +// +const audio = await Service.import("audio"); -import App from 'resource:///com/github/Aylur/ags/app.js' -import * as Utils from 'resource:///com/github/Aylur/ags/utils.js' -import Service from 'resource:///com/github/Aylur/ags/service.js' -import Audio from 'resource:///com/github/Aylur/ags/service/audio.js' -import { Label, Box, Icon, Stack, Button, Slider } from 'resource:///com/github/Aylur/ags/widget.js'; -import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js'; +const volumeIcons = /** @type {const} */ ([ + [101, "overamplified"], + [67, "high"], + [34, "medium"], + [1, "low"], + [0, "muted"], +]); -const iconSubstitute = (item) => { - const substitues = [ - { from: "audio-headset-bluetooth", to: "audio-headphones-symbolic" }, - { from: "audio-card-analog-usb", to: "audio-speakers-symbolic" }, - { from: "audio-card-analog-pci", to: "audio-card-symbolic" }, - ]; - - for (const { from, to } of substitues) { - if (from === item) return to; - } - return item; -}; - -export const SpeakerIndicator = ({ - items = [ - ["101", Icon("audio-volume-overamplified-symbolic")], - ["67", Icon("audio-volume-high-symbolic")], - ["34", Icon("audio-volume-medium-symbolic")], - ["1", Icon("audio-volume-low-symbolic")], - ["0", Icon("audio-volume-muted-symbolic")], - ], - ...props -} = {}) => - Stack({ - ...props, - items, - connections: [ - [ - Audio, - (stack) => { - if (!Audio.speaker) return; - - if (Audio.speaker.isMuted) return (stack.shown = "0"); - - const vol = Audio.speaker.volume * 100; - for (const threshold of [100, 66, 33, 0, -1]) { - if (vol > threshold + 1) return (stack.shown = `${threshold + 1}`); - } - }, - "speaker-changed", - ], - ], - }); - -export const SpeakerPercentLabel = (props) => - Label({ - ...props, - connections: [ - [ - Audio, - (label) => { - if (!Audio.speaker) return; - - const perc = Math.floor(Audio.speaker.volume * 100); - label.label = `${(" " + perc).slice(-3)}%`; - }, - "speaker-changed", - ], - ], - }); - -export const SpeakerSlider = (props) => { - const slider = Slider({ - ...props, - drawValue: false, - onChange: ({ value }) => (Audio.speaker.volume = value), - max: 1.5, - connections: [ - [ - Audio, - (slider) => { - if (!Audio.speaker) return; - - slider.sensitive = !Audio.speaker.isMuted; - slider.value = Audio.speaker.volume; - }, - "speaker-changed", - ], - ], - }); - slider.add_mark(1, 0, null); - slider.add_mark(1, 1, null); - slider.max = 1.5; - return slider; -}; - -export const MicrophoneMuteIndicator = ({ - muted = Icon("microphone-disabled-symbolic"), - unmuted = Icon("microphone-sensitivity-high-symbolic"), - ...props -} = {}) => - Stack({ - ...props, - items: [ - ["true", muted], - ["false", unmuted], - ], - connections: [ - [ - Audio, - (stack) => { - stack.shown = `${Audio.microphone?.isMuted}`; - }, - "microphone-changed", - ], - ], - }); - -export const MuteToggle = (props) => - Button({ - ...props, - className: "qs-button surface", - onClicked: () => execAsync("pactl set-source-mute @DEFAULT_SOURCE@ toggle"), - child: Box({ - children: [ - MicrophoneMuteIndicator({ className: "qs-icon" }), - Label({ - connections: [ - [ - Audio, - (label) => { - if (!Audio.microphone) return; - label.label = Audio.microphone.isMuted ? "Muted" : "Not muted"; - }, - "microphone-changed", - ], - ], - }), - ], +/** @param {import("types/widgets/icon").IconProps} props */ +export const VolumeIndicator = (props) => + Widget.Icon({ + icon: audio.speaker.bind("volume").as((vol) => { + const val = volumeIcons.find( + ([threshold]) => threshold <= vol * 100, + )?.[1]; + return `audio-volume-${val}-symbolic`; }), - connections: [ - [ - Audio, - (button) => { - if (!Audio.microphone) return; - - button.toggleClassName("accent", Audio.microphone.isMuted); - }, - "microphone-changed", - ], - ], - }); - -export const AppMixerToggle = (props) => - ArrowToggle({ - icon: FontIcon({ icon: "", className: "qs-icon" }), - label: Label("App Mixer"), - name: "app-mixer", - toggle: () => opened.value = opened.value === "app-mixer" ? "" : "app-mixer", ...props, }); -export const AppMixer = (props) => { - const AppItem = (stream) => { - const icon = Icon(); - const label = Label({ - xalign: 0, - justify: "left", - wrap: true, - ellipsize: 3, - }); - const percent = Label({ xalign: 1 }); - const slider = Slider({ - hexpand: true, - drawValue: false, - onChange: ({ value }) => { - stream.volume = value; - }, - }); - const sync = () => { - icon.icon = Utils.lookUpIcon(stream.name || '') - ? (stream.name || '') - : "audio-x-generic-symbolic"; - icon.tooltipText = stream.name; - slider.value = stream.volume; - percent.label = `${Math.floor(stream.volume * 100)}%`; - label.label = addElipsis(stream.description || "", 30, "middle"); - }; - const id = stream.connect("changed", sync); - return Box({ - hexpand: true, - children: [ - icon, - Box({ - children: [ - Box({ - vertical: true, - children: [label, slider], - }), - percent, - ], - }), - ], - connections: [["destroy", () => stream.disconnect(id)]], - setup: sync, - }); - }; - - return Box({ - ...props, - vertical: true, - connections: [ - [ - Audio, - (box) => { - box.children = Audio.apps.map((stream) => AppItem(stream)); - }, - ], - ], - }); -}; - -export const StreamSelector = ({ streams = "speakers", ...props } = {}) => - Box({ - ...props, - vertical: true, - connections: [ - [ - Audio, - (box) => { - box.children = Audio[streams] - .map((stream) => - Button({ - child: Box({ - children: [ - Icon({ - icon: iconSubstitute(stream.iconName), - tooltipText: stream.iconName, - }), - Label(stream.description.split(" ").slice(0, 4).join(" ")), - Icon({ - icon: "object-select-symbolic", - hexpand: true, - hpack: "end", - connections: [ - [ - "draw", - (icon) => { - icon.visible = Audio.speaker === stream; - }, - ], - ], - }), - ], - }), - onClicked: () => { - if (streams === "speakers") Audio.speaker = stream; - - if (streams === "microphones") Audio.microphone = stream; - }, - }) - ) - .concat([ - Separator(), - Button({ - onClicked: () => { - execAsync("pavucontrol").catch(print); - App.closeWindow("quicksettings"); - }, - child: Label({ - label: "Settings", - xalign: 0, - }), - }), - ]); - }, - ], - ], +/** @param {import("types/widgets/icon").IconProps} props */ +export const MicrophoneIndicator = (props) => + Widget.Icon(props).hook(audio, (self) => { + self.visible = audio.microphone.is_muted || audio.recorders.length > 0; + if (audio.microphone.is_muted) self.icon = "microphone-disabled-symbolic"; + else if (audio.recorders.length > 0) + self.icon = "microphone-sensitivity-high-symbolic"; }); -// export const MicUseIndicator = ({ className, ...props } = {}) => -// Icon({ -// icon: "microphone-sensitivity-high-symbolic", -// className: `${className} red`, +// const iconSubstitute = (item) => { +// const substitues = [ +// { from: "audio-headset-bluetooth", to: "audio-headphones-symbolic" }, +// { from: "audio-card-analog-usb", to: "audio-speakers-symbolic" }, +// { from: "audio-card-analog-pci", to: "audio-card-symbolic" }, +// ]; +// +// for (const { from, to } of substitues) { +// if (from === item) return to; +// } +// return item; +// }; +// +// +// export const SpeakerPercentLabel = (props) => +// Label({ +// ...props, +// connections: [ +// [ +// Audio, +// (label) => { +// if (!Audio.speaker) return; +// +// const perc = Math.floor(Audio.speaker.volume * 100); +// label.label = `${(" " + perc).slice(-3)}%`; +// }, +// "speaker-changed", +// ], +// ], +// }); +// +// export const SpeakerSlider = (props) => { +// const slider = Slider({ +// ...props, +// drawValue: false, +// onChange: ({ value }) => (Audio.speaker.volume = value), +// max: 1.5, +// connections: [ +// [ +// Audio, +// (slider) => { +// if (!Audio.speaker) return; +// +// slider.sensitive = !Audio.speaker.isMuted; +// slider.value = Audio.speaker.volume; +// }, +// "speaker-changed", +// ], +// ], +// }); +// slider.add_mark(1, 0, null); +// slider.add_mark(1, 1, null); +// slider.max = 1.5; +// return slider; +// }; +// +// export const MuteToggle = (props) => +// Button({ +// ...props, +// classame: "qs-button surface", +// onClicked: () => execAsync("pactl set-source-mute @DEFAULT_SOURCE@ toggle"), +// child: Box({ +// children: [ +// MicrophoneMuteIndicator({ classame: "qs-icon" }), +// Label({ +// connections: [ +// [ +// Audio, +// (label) => { +// if (!Audio.microphone) return; +// label.label = Audio.microphone.isMuted ? "Muted" : "Not muted"; +// }, +// "microphone-changed", +// ], +// ], +// }), +// ], +// }), // connections: [ // [ // Audio, // (button) => { -// log(Audio.recordingApps.map(x => ({desc: x.description, origin: x.origin, type: x.type}))); -// if (!Audio.recordingApps.length) return button.hide(); -// button.show(); +// if (!Audio.microphone) return; +// +// button.toggleClassName("accent", Audio.microphone.isMuted); +// }, +// "microphone-changed", +// ], +// ], +// }); +// +// export const AppMixerToggle = (props) => +// ArrowToggle({ +// icon: FontIcon({ icon: "", className: "qs-icon" }), +// label: Label("App Mixer"), +// name: "app-mixer", +// toggle: () => +// (opened.value = opened.value === "app-mixer" ? "" : "app-mixer"), +// ...props, +// }); +// +// export const AppMixer = (props) => { +// const AppItem = (stream) => { +// const icon = Icon(); +// const label = Label({ +// xalign: 0, +// justify: "left", +// wrap: true, +// ellipsize: 3, +// }); +// const percent = Label({ xalign: 1 }); +// const slider = Slider({ +// hexpand: true, +// drawValue: false, +// onChange: ({ value }) => { +// stream.volume = value; +// }, +// }); +// const sync = () => { +// icon.icon = Utils.lookUpIcon(stream.name || "") +// ? stream.name || "" +// : "audio-x-generic-symbolic"; +// icon.tooltipText = stream.name; +// slider.value = stream.volume; +// percent.label = `${Math.floor(stream.volume * 100)}%`; +// label.label = addElipsis(stream.description || "", 30, "middle"); +// }; +// const id = stream.connect("changed", sync); +// return Box({ +// hexpand: true, +// children: [ +// icon, +// Box({ +// children: [ +// Box({ +// vertical: true, +// children: [label, slider], +// }), +// percent, +// ], +// }), +// ], +// connections: [["destroy", () => stream.disconnect(id)]], +// setup: sync, +// }); +// }; +// +// return Box({ +// ...props, +// vertical: true, +// connections: [ +// [ +// Audio, +// (box) => { +// box.children = Audio.apps.map((stream) => AppItem(stream)); +// }, +// ], +// ], +// }); +// }; +// +// export const StreamSelector = ({ streams = "speakers", ...props } = {}) => +// Box({ +// ...props, +// vertical: true, +// connections: [ +// [ +// Audio, +// (box) => { +// box.children = Audio[streams] +// .map((stream) => +// Button({ +// child: Box({ +// children: [ +// Icon({ +// icon: iconSubstitute(stream.iconName), +// tooltipText: stream.iconName, +// }), +// Label(stream.description.split(" ").slice(0, 4).join(" ")), +// Icon({ +// icon: "object-select-symbolic", +// hexpand: true, +// hpack: "end", +// connections: [ +// [ +// "draw", +// (icon) => { +// icon.visible = Audio.speaker === stream; +// }, +// ], +// ], +// }), +// ], +// }), +// onClicked: () => { +// if (streams === "speakers") Audio.speaker = stream; +// +// if (streams === "microphones") Audio.microphone = stream; +// }, +// }), +// ) +// .concat([ +// Separator(), +// Button({ +// onClicked: () => { +// execAsync("pavucontrol").catch(print); +// App.closeWindow("quicksettings"); +// }, +// child: Label({ +// label: "Settings", +// xalign: 0, +// }), +// }), +// ]); // }, // ], // ], -// ...props, // }); diff --git a/modules/common/ags/modules/battery.js b/modules/common/ags/modules/battery.js index 46458e6..295a2e3 100644 --- a/modules/common/ags/modules/battery.js +++ b/modules/common/ags/modules/battery.js @@ -1,69 +1,28 @@ -import Battery from 'resource:///com/github/Aylur/ags/service/battery.js' -import { Label, Icon, Stack, Box } from 'resource:///com/github/Aylur/ags/widget.js'; - -const icons = (charging) => - Array.from({ length: 11 }, (_, i) => i * 10).map((i) => [ - `${i}`, - Icon({ - className: `${i} ${charging ? "charging" : "discharging"}`, - icon: `battery-level-${i}${charging ? (i === 100 ? "-charged" : "-charging") : "" - }-symbolic`, - }), - ]); - -const Indicators = (charging) => - Stack({ - items: icons(charging), - connections: [ - [ - Battery, - (stack) => { - stack.shown = "100"; //`${Math.floor(Battery.percent / 10) * 10}`; - }, - ], - ], - }); - -export const IconIndicator = ({ - charging = Indicators(true), - discharging = Indicators(false), - ...props -} = {}) => - Stack({ - ...props, - items: [ - ["true", charging], - ["false", discharging], - ], - connections: [ - [ - Battery, - (stack) => { - const { charging, charged } = Battery; - stack.shown = `${charging || charged}`; - stack.toggleClassName("green", Battery.charging || Battery.charged); - stack.toggleClassName("red", Battery.percent < 30); - }, - ], - ], - }); - -export const LevelLabel = ({ ...props }) => - Label({ - ...props, - connections: [[Battery, (label) => (label.label = `${Battery.percent}%`)]], - }); +const battery = await Service.import("battery"); +/** @param {import("types/widgets/box").BoxProps} props */ export const Indicator = ({ ...props }) => - Box({ - ...props, - children: [IconIndicator(), LevelLabel({})], - connections: [ - [ - Battery, - (box) => { - box.visible = Battery.available; - }, - ], + Widget.Box({ + children: [ + Widget.Icon({ + icon: battery.bind("icon_name"), + className: Utils.merge( + [ + battery.bind("charging"), + battery.bind("charged"), + battery.bind("percent"), + ], + (charging, charged, percent) => { + if (charging || charged) return "green"; + if (percent < 30) return "red"; + return ""; + }, + ), + }), + Widget.Label({ + label: battery.bind("percent").as((x) => `${x}%`), + }), ], + visible: battery.bind("available"), + ...props, }); diff --git a/modules/common/ags/modules/bluetooth.js b/modules/common/ags/modules/bluetooth.js index 6887cfb..031f14e 100644 --- a/modules/common/ags/modules/bluetooth.js +++ b/modules/common/ags/modules/bluetooth.js @@ -1,104 +1,92 @@ -import { Spinner, Separator } from "../misc.js"; -import { ArrowToggle } from "../services/quicksettings.js"; +// import { Spinner, Separator } from "../misc.js"; +// import { ArrowToggle } from "../services/quicksettings.js"; -import App from 'resource:///com/github/Aylur/ags/app.js' -import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js' -import { Icon, Label, Box, Button, Stack } from 'resource:///com/github/Aylur/ags/widget.js'; -import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js'; +const bluetooth = await Service.import("bluetooth"); -export const Indicator = ({ - enabled = Icon({ icon: "bluetooth-active-symbolic", className: "enabled" }), - disabled = Icon({ - icon: "bluetooth-disabled-symbolic", - className: "disabled", - }), - ...props -} = {}) => - Stack({ +const connected = Utils.merge( + [bluetooth.bind("enabled"), bluetooth.bind("connected_devices")], + (enabled, devices) => enabled && devices.length > 0, +); + +/** @param {{hideIfDisabled?: boolean} & import("types/widgets/icon").IconProps} props */ +export const Indicator = ({ hideIfDisabled, ...props } = {}) => + Widget.Icon({ + icon: connected.as( + (x) => `bluetooth-${x ? "active" : "disabled"}-symbolic`, + ), + visible: connected.as(x => x || !hideIfDisabled), ...props, - items: [ - ["true", enabled], - ["false", disabled], - ], - connections: [ - [ - Bluetooth, - (stack) => { - stack.shown = `${Bluetooth.enabled && Bluetooth.connectedDevices.length > 0}`; - }, - ], - ], }); -export const Toggle = (props) => - ArrowToggle({ - ...props, - name: "bluetooth", - icon: Indicator(), - label: ConnectedLabel(), - toggle: () => (Bluetooth.enabled = !Bluetooth.enabled), - expand: () => (Bluetooth.enabled = true), - connections: [[Bluetooth, (button) => button.toggleClassName("accent", Bluetooth.enabled)]], - }); - -export const ConnectedLabel = (props) => - Label({ - truncate: "end", - ...props, - connections: [ - [ - Bluetooth, - (label) => { - if (!Bluetooth.enabled) return (label.label = "Disabled"); - - if (Bluetooth.connectedDevices.length === 0) return (label.label = "Not Connected"); - - if (Bluetooth.connectedDevices.length === 1) - return (label.label = Bluetooth.connectedDevices[0].alias); - - label.label = `${Bluetooth.connectedDevices.length} Connected`; - }, - ], - ], - }); - -export const Devices = (props) => - Box({ - ...props, - vertical: true, - connections: [ - [ - Bluetooth, - (box) => { - box.children = Bluetooth.devices - .map((device) => - Button({ - onClicked: () => device.setConnection(!device.connected), - hexpand: false, - child: Box({ - children: [ - Icon(device.iconName + "-symbolic"), - Label(device.name), - Box({ hexpand: true }), - device._connecting ? Spinner() : Label(device.connected ? "Disconnect" : "Connect"), - ], - }), - }) - ) - .concat([ - Separator(), - Button({ - onClicked: () => { - execAsync("blueberry").catch(print); - App.closeWindow("quicksettings"); - }, - child: Label({ - label: "Settings", - xalign: 0, - }), - }), - ]); - }, - ], - ], - }); +// export const Toggle = (props) => +// ArrowToggle({ +// ...props, +// name: "bluetooth", +// icon: Indicator(), +// label: ConnectedLabel(), +// toggle: () => (Bluetooth.enabled = !Bluetooth.enabled), +// expand: () => (Bluetooth.enabled = true), +// connections: [[Bluetooth, (button) => button.toggleClassName("accent", Bluetooth.enabled)]], +// }); +// +// export const ConnectedLabel = (props) => +// Label({ +// truncate: "end", +// ...props, +// connections: [ +// [ +// Bluetooth, +// (label) => { +// if (!Bluetooth.enabled) return (label.label = "Disabled"); +// +// if (Bluetooth.connectedDevices.length === 0) return (label.label = "Not Connected"); +// +// if (Bluetooth.connectedDevices.length === 1) +// return (label.label = Bluetooth.connectedDevices[0].alias); +// +// label.label = `${Bluetooth.connectedDevices.length} Connected`; +// }, +// ], +// ], +// }); +// +// export const Devices = (props) => +// Box({ +// ...props, +// vertical: true, +// connections: [ +// [ +// Bluetooth, +// (box) => { +// box.children = Bluetooth.devices +// .map((device) => +// Button({ +// onClicked: () => device.setConnection(!device.connected), +// hexpand: false, +// child: Box({ +// children: [ +// Icon(device.iconName + "-symbolic"), +// Label(device.name), +// Box({ hexpand: true }), +// device._connecting ? Spinner() : Label(device.connected ? "Disconnect" : "Connect"), +// ], +// }), +// }) +// ) +// .concat([ +// Separator(), +// Button({ +// onClicked: () => { +// execAsync("blueberry").catch(print); +// App.closeWindow("quicksettings"); +// }, +// child: Label({ +// label: "Settings", +// xalign: 0, +// }), +// }), +// ]); +// }, +// ], +// ], +// }); diff --git a/modules/common/ags/modules/clock.js b/modules/common/ags/modules/clock.js index 4c60da6..6fae55a 100644 --- a/modules/common/ags/modules/clock.js +++ b/modules/common/ags/modules/clock.js @@ -1,17 +1,14 @@ -import { Label } from 'resource:///com/github/Aylur/ags/widget.js'; -const { DateTime } = imports.gi.GLib; +import GLib from "gi://GLib"; -export const Clock = ({ - format = "%a %d %b %H:%M ", - interval = 1000, - ...props -} = {}) => - Label({ +export const clock = Variable(GLib.DateTime.new_now_local(), { + poll: [1000, () => GLib.DateTime.new_now_local()], +}); + +/** + * @param {{format?: string} & import("types/widgets/label").LabelProps} props + */ +export const Clock = ({ format = "%a %d %b %H:%M ", ...props } = {}) => + Widget.Label({ ...props, - connections: [ - [ - interval, - (label) => (label.label = DateTime.new_now_local().format(format)), - ], - ], + label: Utils.derive([clock], (c) => c.format(format) || "").bind(), }); diff --git a/modules/common/ags/modules/network.js b/modules/common/ags/modules/network.js index 968f48d..79fd6f8 100644 --- a/modules/common/ags/modules/network.js +++ b/modules/common/ags/modules/network.js @@ -1,126 +1,127 @@ -import { ArrowToggle } from "../services/quicksettings.js"; -import { Separator } from "../misc.js"; +// import { ArrowToggle } from "../services/quicksettings.js"; +// import { Separator } from "../misc.js"; -import App from 'resource:///com/github/Aylur/ags/app.js' -import Network from 'resource:///com/github/Aylur/ags/service/network.js' -import { Label, Icon, Box, Stack, Button } from 'resource:///com/github/Aylur/ags/widget.js'; -import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js'; +const network = await Service.import("network"); -export const SSIDLabel = (props) => - Label({ - truncate: "end", - ...props, - connections: [ - [ - Network, - (label) => { - if (Network.primary === "wifi") label.label = Network.wifi?.ssid || "Not Connected"; - else - label.label = - Network.wired?.internet === "connected" || Network.wired?.internet === "connection" - ? "Wired" - : "Not Connected"; - }, - ], - ], - }); - -export const WifiStrengthLabel = (props) => - Label({ - ...props, - connections: [[Network, (label) => (label.label = `${Network.wifi?.strength || -1}`)]], - }); - -export const Indicator = () => Stack({ - items: [ - ['wifi', Icon({ - connections: [[Network, self => { - self.icon = Network.wifi?.iconName || ''; - }]], - })], - ['wired', Icon({ - connections: [[Network, self => { - self.icon = Network.wired?.iconName || ''; - }]], - })], - ], - connections: [[Network, self => { self.shown = Network.primary || "wifi" }]], -}); - -export const Toggle = (props) => - ArrowToggle({ - ...props, - name: "network", - icon: Indicator(), - label: SSIDLabel(), - toggle: Network.toggleWifi, - expand: () => { - Network.wifi.enabled = true; - Network.wifi.scan(); +/** @param {import("types/widgets/icon").IconProps} props*/ +export const Indicator = (props) => + Widget.Stack({ + children: { + wifi: Widget.Icon({ + icon: network.wifi.bind("icon_name"), + ...props, + }), + wired: Widget.Icon({ + icon: network.wired.bind("icon_name"), + ...props, + }), }, - connections: [ - [ - Network, - (button) => { - button.toggleClassName("accent", Network.wifi?.enabled); - }, - ], - ], + shown: network.bind("primary").as((p) => p || "wifi"), }); -const icons = [ - { value: 80, icon: "network-wireless-signal-excellent-symbolic" }, - { value: 60, icon: "network-wireless-signal-good-symbolic" }, - { value: 40, icon: "network-wireless-signal-ok-symbolic" }, - { value: 20, icon: "network-wireless-signal-weak-symbolic" }, - { value: 0, icon: "network-wireless-signal-none-symbolic" }, -]; +// export const SSIDLabel = (props) => +// Label({ +// truncate: "end", +// ...props, +// connections: [ +// [ +// Network, +// (label) => { +// if (Network.primary === "wifi") +// label.label = Network.wifi?.ssid || "Not Connected"; +// else +// label.label = +// Network.wired?.internet === "connected" || +// Network.wired?.internet === "connection" +// ? "Wired" +// : "Not Connected"; +// }, +// ], +// ], +// }); +// +// export const WifiStrengthLabel = (props) => +// Label({ +// ...props, +// connections: [ +// [Network, (label) => (label.label = `${Network.wifi?.strength || -1}`)], +// ], +// }); -export const Selection = (props) => - Box({ - ...props, - vertical: true, - connections: [ - [ - Network, - (box) => { - box.children = Network.wifi?.accessPoints - .reduce((acc, x) => { - if (!acc[x.bssid]) - acc.push(x) - return acc; - }, []) - .map((ap) => - Button({ - onClicked: () => execAsync(`nmcli device wifi connect ${ap.bssid}`), - child: Box({ - children: [ - Icon(icons.find(({ value }) => value <= ap.strength).icon), - Label(ap.ssid), - ap.active && - Icon({ - icon: "object-select-symbolic", - hexpand: true, - hpack: "end", - }), - ], - }), - }) - ) - .concat([ - Separator(), - Button({ - onClicked: () => { - execAsync("gnome-control-center").catch(print); - App.closeWindow("quicksettings"); - }, - child: Label({ - label: "Settings", - xalign: 0, - }), - }), - ]); - }, - ], - ], - }); +// export const Toggle = (props) => +// ArrowToggle({ +// ...props, +// name: "network", +// icon: Indicator(), +// label: SSIDLabel(), +// toggle: Network.toggleWifi, +// expand: () => { +// Network.wifi.enabled = true; +// Network.wifi.scan(); +// }, +// connections: [ +// [ +// Network, +// (button) => { +// button.toggleClassName("accent", Network.wifi?.enabled); +// }, +// ], +// ], +// }); +// +// const icons = [ +// { value: 80, icon: "network-wireless-signal-excellent-symbolic" }, +// { value: 60, icon: "network-wireless-signal-good-symbolic" }, +// { value: 40, icon: "network-wireless-signal-ok-symbolic" }, +// { value: 20, icon: "network-wireless-signal-weak-symbolic" }, +// { value: 0, icon: "network-wireless-signal-none-symbolic" }, +// ]; +// +// export const Selection = (props) => +// Box({ +// ...props, +// vertical: true, +// connections: [ +// [ +// Network, +// (box) => { +// box.children = Network.wifi?.accessPoints +// .reduce((acc, x) => { +// if (!acc[x.bssid]) acc.push(x); +// return acc; +// }, []) +// .map((ap) => +// Button({ +// onClicked: () => +// execAsync(`nmcli device wifi connect ${ap.bssid}`), +// child: Box({ +// children: [ +// Icon(icons.find(({ value }) => value <= ap.strength).icon), +// Label(ap.ssid), +// ap.active && +// Icon({ +// icon: "object-select-symbolic", +// hexpand: true, +// hpack: "end", +// }), +// ], +// }), +// }), +// ) +// .concat([ +// Separator(), +// Button({ +// onClicked: () => { +// execAsync("gnome-control-center").catch(print); +// App.closeWindow("quicksettings"); +// }, +// child: Label({ +// label: "Settings", +// xalign: 0, +// }), +// }), +// ]); +// }, +// ], +// ], +// }); diff --git a/modules/common/ags/modules/notifications.js b/modules/common/ags/modules/notifications.js index e9832f7..3a7fa67 100644 --- a/modules/common/ags/modules/notifications.js +++ b/modules/common/ags/modules/notifications.js @@ -1,275 +1,249 @@ -import { FontIcon } from "../misc.js"; +// import { FontIcon } from "../misc.js"; -const { GLib } = imports.gi; -import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js' -import { lookUpIcon, timeout } from 'resource:///com/github/Aylur/ags/utils.js'; +const notifications = await Service.import("notifications"); +notifications.popupTimeout = 2000; //in seconds +notifications.forceTimeout = true; //force all notifications to timeout -import Widget from 'resource:///com/github/Aylur/ags/widget.js'; -import { Box, Icon, Label, EventBox, Button, Stack, Revealer } from 'resource:///com/github/Aylur/ags/widget.js'; - -export const Indicator = ({ ...props }) => - Box({ +/** @param {import("types/widgets/icon").IconProps} props */ +export const DNDIndicator = (props) => + Widget.Icon({ + visible: notifications.bind("dnd"), + icon: "notifications-disabled-symbolic", ...props, - connections: [ - [ - Notifications, - (box) => { - box.visible = Notifications.notifications.length > 0 && !Notifications.dnd; - }, - ], - ], + }); + +/** @param {import("types/widgets/box").BoxProps} props */ +export const Indicator = ({ ...props }) => + Widget.Box({ + visible: notifications.bind("notifications").as((x) => x.length > 0), children: [ - Icon("preferences-system-notifications-symbolic"), - Revealer({ + Widget.Icon({ icon: "preferences-system-notifications-symbolic" }), + Widget.Revealer({ transition: "slide_right", - properties: [ - ["current", null], - [ - "update", - (rev, id, open) => { - if (!id) return; - - // Only close the notification if it is the currently displayed. - if (rev._current !== id && !open) return; - - if (rev._current === id && !open) { - rev.reveal_child = false; - return; - } - - rev._current = id; - const notif = Notifications.getNotification(id); - rev.child.label = `${notif.summary?.substring(0, 18)?.trim()}: ${notif.body?.substring(0, 45)?.trim()}`.replaceAll("\n", " "); - rev.reveal_child = true; - }, - ], - ], - connections: [ - [Notifications, (label, id) => label._update(label, id, true), "notified"], - [Notifications, (label, id) => label._update(label, id, false), "dismissed"], - [Notifications, (label, id) => label._update(label, id, false), "closed"], - ], - child: Label({ + revealChild: notifications.bind("popups").as((x) => x.length > 0), + child: Widget.Label({ use_markup: true, truncate: "end", wrap: false, - label: "", - }), - }), - ], - }); - -const NotificationIcon = ({ appEntry, appIcon, image }) => { - if (image) { - return Widget.Box({ - vpack: "start", - hexpand: false, - className: "icon img", - css: ` - background-image: url("${image}"); - background-size: contain; - background-repeat: no-repeat; - background-position: center; - min-width: 78px; - min-height: 78px; - `, - }); - } - - let icon = "dialog-information-symbolic"; - if (lookUpIcon(appIcon)) icon = appIcon; - - if (lookUpIcon(appEntry)) icon = appEntry; - - return Widget.Box({ - vpack: "start", - hexpand: false, - className: "icon", - css: ` - min-width: 78px; - min-height: 78px; - `, - children: [ - Widget.Icon({ - icon, - size: 58, - hpack: "center", - hexpand: true, - vpack: "center", - vexpand: true, - }), - ], - }); -}; - -export const Notification = n => Widget.EventBox({ - className: `surface r20 p10 notification ${n.urgency}`, - css: "margin: 8px 0;", - onPrimaryClick: () => n.dismiss(), - properties: [['hovered', false]], - onHover: self => { - if (self._hovered) - return; - - // if there are action buttons and they are hovered - // EventBox onHoverLost will fire off immediately, - // so to prevent this we delay it - timeout(300, () => self._hovered = true); - }, - onHoverLost: self => { - if (!self._hovered) - return; - - self._hovered = false; - n.dismiss(); - }, - vexpand: false, - child: Widget.Box({ - vertical: true, - children: [ - Widget.Box({ - children: [ - NotificationIcon(n), - Widget.Box({ - hexpand: true, - vertical: true, - children: [ - Widget.Box({ - children: [ - Widget.Label({ - className: 'title', - xalign: 0, - justification: 'left', - hexpand: true, - maxWidthChars: 24, - truncate: 'end', - wrap: true, - label: n.summary, - useMarkup: true, - }), - Widget.Button({ - className: 'close-button', - vpack: 'start', - child: Widget.Icon('window-close-symbolic'), - onClicked: n.close.bind(n), - }), - ], - }), - Widget.Label({ - className: 'description', - hexpand: true, - useMarkup: true, - xalign: 0, - justification: 'left', - label: n.body, - wrap: true, - }), - ], + label: notifications.bind("popups").as((x) => { + const notif = x[x.length - 1]; + // Keep the text of the old notif for the fade out animation. + if (!notif) return old_notif; + const summary = notif.summary.substring(0, 18).trim(); + const body = notif.body.substring(0, 45).trim(); + old_notif = `${summary}: ${body}`.replaceAll("\n", " "); + return old_notif; }), - ], - }), - Widget.Box({ - className: 'actions', - children: n.actions.map(({ id, label }) => Widget.Button({ - className: 'action-button', - onClicked: () => n.invoke(id), - hexpand: true, - child: Widget.Label(label), - })), - }), - ], - }), -}); - -export const List = (props) => - Box({ - ...props, - vertical: true, - connections: [ - [ - Notifications, - (box) => { - box.children = Notifications.notifications.map((n) => Notification(n)); - - box.visible = Notifications.notifications.length > 0; - }, - ], - ], - }); - -export const Placeholder = (props) => - Box({ - vertical: true, - vpack: "center", - hpack: "center", - ...props, - children: [ - Label({ label: "󰂛", css: "margin-top: 150px;" }), - Label({ label: "Your inbox is empty", css: "margin-bottom: 150px;" }), - ], - connections: [[Notifications, (box) => (box.visible = Notifications.notifications.length === 0)]], - }); - -export const ClearButton = (props) => - Button({ - ...props, - onClicked: () => Notifications.clear(), - connections: [[Notifications, (button) => (button.sensitive = Notifications.notifications.length > 0)]], - child: Box({ - children: [ - Label("Clear "), - Stack({ - items: [ - ["true", Icon("user-trash-full-symbolic")], - ["false", Icon("user-trash-symbolic")], - ], - connections: [ - [ - Notifications, - (stack) => { - stack.shown = `${Notifications.notifications.length > 0}`; - }, - ], - ], }), - ], - }), - }); - -export const DNDIndicator = ({ - silent = Icon("notifications-disabled-symbolic"), - noisy = Icon("preferences-system-notifications-symbolic"), - ...props -} = {}) => - Stack({ + }), + ], ...props, - items: [ - ["true", silent], - ["false", noisy], - ], - connections: [ - [ - Notifications, - (stack) => { - stack.shown = `${Notifications.dnd}`; - }, - ], - ], }); +let old_notif = ""; -export const DNDToggle = (props) => - Button({ - ...props, - onClicked: () => { - Notifications.dnd = !Notifications.dnd; - }, - child: DNDIndicator(), - connections: [ - [ - Notifications, - (button) => { - button.toggleClassName("on", Notifications.dnd); - }, - ], - ], - }); +// const NotificationIcon = ({ appEntry, appIcon, image }) => { +// if (image) { +// return Widget.Box({ +// vpack: "start", +// hexpand: false, +// className: "icon img", +// css: ` +// background-image: url("${image}"); +// background-size: contain; +// background-repeat: no-repeat; +// background-position: center; +// min-width: 78px; +// min-height: 78px; +// `, +// }); +// } +// +// let icon = "dialog-information-symbolic"; +// if (lookUpIcon(appIcon)) icon = appIcon; +// +// if (lookUpIcon(appEntry)) icon = appEntry; +// +// return Widget.Box({ +// vpack: "start", +// hexpand: false, +// className: "icon", +// css: ` +// min-width: 78px; +// min-height: 78px; +// `, +// children: [ +// Widget.Icon({ +// icon, +// size: 58, +// hpack: "center", +// hexpand: true, +// vpack: "center", +// vexpand: true, +// }), +// ], +// }); +// }; +// +// export const Notification = (n) => +// Widget.EventBox({ +// className: `surface r20 p10 notification ${n.urgency}`, +// css: "margin: 8px 0;", +// onPrimaryClick: () => n.dismiss(), +// properties: [["hovered", false]], +// onHover: (self) => { +// if (self._hovered) return; +// +// // if there are action buttons and they are hovered +// // EventBox onHoverLost will fire off immediately, +// // so to prevent this we delay it +// timeout(300, () => (self._hovered = true)); +// }, +// onHoverLost: (self) => { +// if (!self._hovered) return; +// +// self._hovered = false; +// n.dismiss(); +// }, +// vexpand: false, +// child: Widget.Box({ +// vertical: true, +// children: [ +// Widget.Box({ +// children: [ +// NotificationIcon(n), +// Widget.Box({ +// hexpand: true, +// vertical: true, +// children: [ +// Widget.Box({ +// children: [ +// Widget.Label({ +// className: "title", +// xalign: 0, +// justification: "left", +// hexpand: true, +// maxWidthChars: 24, +// truncate: "end", +// wrap: true, +// label: n.summary, +// useMarkup: true, +// }), +// Widget.Button({ +// className: "close-button", +// vpack: "start", +// child: Widget.Icon("window-close-symbolic"), +// onClicked: n.close.bind(n), +// }), +// ], +// }), +// Widget.Label({ +// className: "description", +// hexpand: true, +// useMarkup: true, +// xalign: 0, +// justification: "left", +// label: n.body, +// wrap: true, +// }), +// ], +// }), +// ], +// }), +// Widget.Box({ +// className: "actions", +// children: n.actions.map(({ id, label }) => +// Widget.Button({ +// className: "action-button", +// onClicked: () => n.invoke(id), +// hexpand: true, +// child: Widget.Label(label), +// }), +// ), +// }), +// ], +// }), +// }); +// +// export const List = (props) => +// Box({ +// ...props, +// vertical: true, +// connections: [ +// [ +// Notifications, +// (box) => { +// box.children = Notifications.notifications.map((n) => +// Notification(n), +// ); +// +// box.visible = Notifications.notifications.length > 0; +// }, +// ], +// ], +// }); +// +// export const Placeholder = (props) => +// Box({ +// vertical: true, +// vpack: "center", +// hpack: "center", +// ...props, +// children: [ +// Label({ label: "󰂛", css: "margin-top: 150px;" }), +// Label({ label: "Your inbox is empty", css: "margin-bottom: 150px;" }), +// ], +// connections: [ +// [ +// Notifications, +// (box) => (box.visible = Notifications.notifications.length === 0), +// ], +// ], +// }); +// +// export const ClearButton = (props) => +// Button({ +// ...props, +// onClicked: () => Notifications.clear(), +// connections: [ +// [ +// Notifications, +// (button) => (button.sensitive = Notifications.notifications.length > 0), +// ], +// ], +// child: Box({ +// children: [ +// Label("Clear "), +// Stack({ +// items: [ +// ["true", Icon("user-trash-full-symbolic")], +// ["false", Icon("user-trash-symbolic")], +// ], +// connections: [ +// [ +// Notifications, +// (stack) => { +// stack.shown = `${Notifications.notifications.length > 0}`; +// }, +// ], +// ], +// }), +// ], +// }), +// }); +// +// export const DNDToggle = (props) => +// Button({ +// ...props, +// onClicked: () => { +// Notifications.dnd = !Notifications.dnd; +// }, +// child: DNDIndicator(), +// connections: [ +// [ +// Notifications, +// (button) => { +// button.toggleClassName("on", Notifications.dnd); +// }, +// ], +// ], +// }); diff --git a/modules/common/ags/shell.nix b/modules/common/ags/shell.nix new file mode 100644 index 0000000..0d68403 --- /dev/null +++ b/modules/common/ags/shell.nix @@ -0,0 +1,6 @@ +{pkgs ? import {}}: + pkgs.mkShell { + packages = with pkgs; [ + biome + ]; + } diff --git a/modules/common/tsconfig.json b/modules/common/ags/tsconfig.json similarity index 93% rename from modules/common/tsconfig.json rename to modules/common/ags/tsconfig.json index f6cc8d2..f03f2d1 100644 --- a/modules/common/tsconfig.json +++ b/modules/common/ags/tsconfig.json @@ -11,8 +11,8 @@ "noImplicitAny": false, "baseUrl": ".", "typeRoots": [ - "ags/types" + "./types" ], "skipLibCheck": true } -} +} \ No newline at end of file diff --git a/modules/common/ags/types b/modules/common/ags/types new file mode 120000 index 0000000..61c5a24 --- /dev/null +++ b/modules/common/ags/types @@ -0,0 +1 @@ +/nix/store/0wizyq5vnr0l5nyrvjnya732hxnk2cvw-ags-1.8.2/share/com.github.Aylur.ags/types \ No newline at end of file diff --git a/modules/dwl/default.nix b/modules/dwl/default.nix index 25c8dba..2f6c7de 100644 --- a/modules/dwl/default.nix +++ b/modules/dwl/default.nix @@ -23,7 +23,6 @@ environment.systemPackages = with pkgs; [ dwl polkit_gnome - inputs.ags.packages.x86_64-linux.default wineWowPackages.stable wineWowPackages.waylandFull winetricks diff --git a/modules/river/default.nix b/modules/river/default.nix index e00aafb..ca4693f 100644 --- a/modules/river/default.nix +++ b/modules/river/default.nix @@ -51,8 +51,6 @@ }; environment.systemPackages = with pkgs; [ - # TODO: Remove this - inputs.ags.packages.x86_64-linux.default gnome.gnome-bluetooth polkit_gnome wineWowPackages.stable