ags: add center-window and logout-menu windows and more

This commit is contained in:
retrozinndev
2025-02-12 13:39:38 -03:00
parent 36ee8c6ff5
commit be2731516e
28 changed files with 576 additions and 232 deletions
+1
View File
@@ -26,6 +26,7 @@ App.start({
Wireplumber.getDefault().getDefaultSink().connect("notify::volume", () => Wireplumber.getDefault().getDefaultSink().connect("notify::volume", () =>
!Windows.isVisible(ControlCenter) && triggerOSD(OSDModes.SINK)); !Windows.isVisible(ControlCenter) && triggerOSD(OSDModes.SINK));
} }
}); });
+1 -1
View File
@@ -19,7 +19,7 @@ export function handleArguments(request: string): any {
return handleVolumeArgs(args); return handleVolumeArgs(args);
case "reload": case "reload":
restartInstance({ log: false, instanceName: "astal" }); restartInstance();
return "Reloading instance..." return "Reloading instance..."
default: default:
+69 -35
View File
@@ -1,20 +1,45 @@
import AstalNotifd from "gi://AstalNotifd"; import AstalNotifd from "gi://AstalNotifd";
import { timeout } from "astal/time"; import { timeout } from "astal/time";
import { Connectable } from "astal/binding";
import { GObject, register, property, signal } from "astal";
import { Windows } from "../windows";
const notifd: AstalNotifd.Notifd = new AstalNotifd.Notifd({ @register()
ignoreTimeout: false, class Notifications extends GObject.Object implements Connectable {
private static instance: Notifications;
private notifd: AstalNotifd.Notifd;
public notifications: Array<AstalNotifd.Notification> = [];
public notificationHistory: Array<AstalNotifd.Notification> = [];
@signal()
declare "notification-added": (notification: AstalNotifd.Notification) => void;
public static getDefault(): Notifications {
if(!Notifications.instance) {
Notifications.instance = new Notifications();
this.instance._init();
}
return Notifications.instance;
}
constructor() {
super();
this.notifd = new AstalNotifd.Notifd({
ignoreTimeout: true,
dontDisturb: false dontDisturb: false
}); } as AstalNotifd.Notifd.ConstructorProps);
export let notifications: Array<AstalNotifd.Notification> = getNotifd().notifications; this.getNotifd().connect("notified", (_source: AstalNotifd.Notifd, id: number, _replaced: boolean) => {
export let notificationHistory: Array<AstalNotifd.Notification> = []; this.addNotification(this.getNotifd().get_notification(id));
});
}
notifd.connect("notified", (_source: AstalNotifd.Notifd, id: number, _replaced: boolean) => { public addNotification(notification: AstalNotifd.Notification) {
addNotification(getNotifd().get_notification(id)); this.prependArray(this.notifications, this.getNotifd().get_notification(notification.id));
});
function addNotification(notification: AstalNotifd.Notification) {
prependArray(notifications, getNotifd().get_notification(notification.id));
// default timeout if undefined // default timeout if undefined
let notificationTimeout = 4000; let notificationTimeout = 4000;
@@ -28,36 +53,45 @@ function addNotification(notification: AstalNotifd.Notification) {
break; break;
} }
notification.urgency !== AstalNotifd.Urgency.CRITICAL && timeout(notificationTimeout, () => { notification.urgency !== AstalNotifd.Urgency.CRITICAL ?
notificationTimeout--; timeout(notificationTimeout, () => {
if(notificationTimeout === 0) { this.notifications.map((item: AstalNotifd.Notification) =>
removeNotification(notification.id); item.id === notification.id && (() => {
addToNotificationHistory(notification); this.removeNotification(notification.id);
}; this.addToNotificationHistory(notification);
}); })())
} })
: this.addToNotificationHistory(notification);
export function removeNotification(notificationId: number) { this.emit("notification-added", notification);
notifications = notifications.filter((notification: AstalNotifd.Notification) => }
public removeNotification(notificationId: number) {
if(this.notifications.length === 1)
Windows.close(Windows.getWindow("floating-notifications")!);
this.notifications = this.notifications.filter((notification: AstalNotifd.Notification) =>
notification.id !== notificationId); notification.id !== notificationId);
}
function addToNotificationHistory(notification: AstalNotifd.Notification) { this.emit("notification-removed", notificationId);
prependArray(notificationHistory, notification); }
}
export function removeFromNotificationHistory(notificationId: number) { public addToNotificationHistory(notification: AstalNotifd.Notification) {
notifications = notifications.filter((curNotification: AstalNotifd.Notification) => this.prependArray(this.notificationHistory, notification);
}
public removeFromNotificationHistory(notificationId: number) {
this.notificationHistory = this.notificationHistory.filter((curNotification: AstalNotifd.Notification) =>
curNotification.id !== notificationId); curNotification.id !== notificationId);
} }
function prependArray(array: Array<any>, item: any) { private prependArray(array: Array<any>, item: any): Array<any> {
let tmpArray = array; let tmpArray = array.reverse();
tmpArray.reverse();
tmpArray.push(item); tmpArray.push(item);
array = tmpArray.reverse(); return tmpArray.reverse();
} }
export function getNotifd(): AstalNotifd.Notifd { public getNotifd(): AstalNotifd.Notifd {
return notifd; return this.notifd;
}
} }
+4 -16
View File
@@ -1,30 +1,18 @@
import { monitorFile, Process } from "astal"; import { monitorFile, Process } from "astal";
import { getUserDirs } from "./user";
import { App } from "astal/gtk3"; import { App } from "astal/gtk3";
const monitoringPaths = [ "./scripts", "./window", "./app.ts", "env.d.ts" ]; const monitoringPaths = [ "./scripts", "./window", "./app.ts", "env.d.ts" ];
export interface InstanceProps { export function restartInstance(instanceName?: string): void {
instanceName?: string; Process.exec_async(`astal -q ${ instanceName || App.instanceName || "astal" }`, () => {});
log?: boolean; Process.exec_async(`ags run`, () => {});
}
export function restartInstance(props: InstanceProps = { instanceName: "astal", log: false }): void {
Process.exec_async(`astal -q ${props.instanceName}`, () => {});
Process.exec_async(`ags run ${ props.log && `--log-file
${ getUserDirs().cache}/ags-${ App.instanceName || "astal" }.log` }`.replaceAll('\n', ' ').trim(),
() => {}
)
} }
export function monitorPaths(): void { export function monitorPaths(): void {
monitoringPaths.map((path: string) => { monitoringPaths.map((path: string) => {
monitorFile( monitorFile(
path, path,
() => restartInstance({ () => restartInstance()
instanceName: App.instanceName || "astal",
log: true
})
) )
}); });
} }
+1 -1
View File
@@ -23,7 +23,7 @@ export function reloadStyle(): void {
export function compileStyle(): void { export function compileStyle(): void {
console.log("[LOG] Compiling sass (stylesheet)"); console.log("[LOG] Compiling sass (stylesheet)");
Process.exec(`mkdir -p ${stylePath}`); Process.exec(`mkdir -p ${stylePath}`);
Process.exec(`bash -c "sass -I ./style ./style.scss ${stylePath}/style.css"`); Process.exec(`sh -c "sass -I ./style ./style.scss ${stylePath}/style.css"`);
} }
export function applyStyle(): void { export function applyStyle(): void {
+9 -46
View File
@@ -1,55 +1,18 @@
@use "sass:color"; @use "sass:color";
@use "./style/bar";
@use "./style/wal"; @use "./style/wal";
@use "./style/mixins";
@use "./style/bar";
@use "./style/osd"; @use "./style/osd";
@use "./style/control-center"; @use "./style/control-center";
@use "./style/center-window";
* { * {
all: unset; @include mixins.reset-props;
transition: 120ms linear;
color: color.adjust($color: wal.$foreground, $lightness: 15%);
} }
.button-row { window * {
& > button { @include mixins.default-styles;
background: color.scale($color: wal.$foreground, $lightness: -30%, $alpha: 70%);
margin: 0 1px;
border-radius: 2px;
&:hover {
background: color.scale($color: wal.$foreground, $lightness: -30%, $alpha: 100%);
}
&:first-child {
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
}
&:last-child {
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
}
}
menu {
padding: 4px;
background: wal.$background;
border-radius: 14px;
& separator {
margin: 0 4px;
color: wal.$background;
}
& menuitem {
padding: 8px 0px;
border-radius: 10px;
font-size: 12px;
font-weight: 600;
&:hover {
background: wal.$color1;
}
}
} }
+66 -61
View File
@@ -1,39 +1,31 @@
@use "sass:color"; @use "sass:color";
@use "./wal";
@use "./mixins"; @use "./mixins";
@use "./colors";
.bar-container { .bar-container {
@include mixins.reset-props;
@include mixins.default-styles;
padding: 6px; padding: 6px;
padding-bottom: 0px; padding-bottom: 0px;
& {
button {
padding: 6px 8px;
border-radius: 12px;
&:hover {
background: wal.$color1;
}
}
label { label {
font-size: 12px; @include mixins.reset-props;
font-family: "Cantarell", "Noto Sans";
font-weight: 500;
}
font-size: 12px;
font-weight: 500;
} }
// Style widget groups // Style widget groups
& > .bar-centerbox > * { & > .bar-centerbox > * {
background: rgba($color: wal.$background, $alpha: .6); background: colors.$bg-translucent;
padding: 5px; padding: 5px;
border-radius: 18px; border-radius: 18px;
// Style widgets // Style widgets
& > *, & > button,
& > * > button & > eventbox,
& > * { & > box {
margin: 0 2px; margin: 0 2px;
&:first-child { &:first-child {
@@ -43,22 +35,33 @@
&:last-child { &:last-child {
margin-right: 0; margin-right: 0;
} }
& > button,
& > eventbox > box {
padding: 4px 8px;
border-radius: 12px;
}
& > button:hover,
& > eventbox:hover > box {
background: colors.$bg-primary;
}
} }
} }
.workspaces { .workspaces {
@include mixins.reset-props;
padding: 2px 2px; padding: 2px 2px;
& button { & button {
all: unset;
border-radius: 16px; border-radius: 16px;
transition: 80ms linear; transition: 80ms linear;
padding: 12px 12px; padding: 12px 12px;
background: wal.$color1; background: colors.$bg-tertiary;
margin: 1px 2px; margin: 1px 2px;
&.focus { &.focus {
background: wal.$foreground; background: colors.$fg-primary;
padding: 12px 20px; padding: 12px 20px;
} }
} }
@@ -76,58 +79,47 @@
font-size: 9px; font-size: 9px;
font-family: monospace; font-family: monospace;
font-weight: 600; font-weight: 600;
color: color.adjust($color: wal.$foreground, $lightness: -11%); color: colors.$fg-disabled;
margin-top: 1px; margin-top: 0px;
} }
& > .title { & > .title {
font-size: 11.5px; font-size: 12px;
font-weight: 500; font-weight: 500;
margin-top: -2px; margin-top: -2px;
} }
} }
} }
.logo button {
padding: 0 11px;
padding-right: 16px;
& label {
font-size: 14px;
}
}
.media-eventbox { .media-eventbox {
& > .media > box { & > .media {
border-radius: 12px; border-radius: 12px;
background: wal.$color1; background: colors.$bg-primary;
padding: 0 7px; padding: 0 8px;
}
& .icon { & .nf {
margin-right: 6px; margin-right: 4px;
font-size: 14px; font-size: 14px;
} }
}
&.reveal {
& .media > box {
transition: 50ms linear;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
& .media-controls { & .media-controls {
transition: none;
padding-left: 6px; padding-left: 6px;
border-top-right-radius: 12px; border-top-right-radius: 12px;
border-bottom-right-radius: 12px; border-bottom-right-radius: 12px;
transition: unset; background: linear-gradient(to left, colors.$bg-primary 45px, colors.$bg-primary);
background: linear-gradient(to left, color.adjust($color: wal.$color1, $lightness: -15%) 45px, wal.$color1);
& > button { & > button {
margin: 0px 1px; margin: 4px 1px;
border-radius: 4px; border-radius: 4px;
label {
font-size: 8px;
}
&:hover { &:hover {
background: wal.$color2; background: colors.$bg-secondary;
} }
&:first-child { &:first-child {
@@ -143,6 +135,13 @@
} }
} }
} }
&.reveal {
& .media > box {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
} }
} }
@@ -170,26 +169,32 @@
} }
.audio { .audio {
&:hover > box { @include mixins.reset-props;
background: wal.$color1;
}
& .notification-bell { &:hover > box {
padding-left: 10px; background: colors.$bg-primary;
padding-right: 4px;
} }
& > box { & > box {
padding: 0 9px; padding: 0 8px;
border-radius: 12px; border-radius: 12px;
& > * > * {
margin: 0 2px;
} }
& .sink .icon { & .nf {
margin-right: 6px; margin: {
right: 3px;
left: 2px;
};
font-size: 12px;
} }
& .source .icon { & .bell {
margin-right: 4px; margin: 0 4px;
}
} }
} }
} }
+40
View File
@@ -0,0 +1,40 @@
@use "sass:color";
@use "./wal";
@use "./functions" as funs; // Did you know that you can use the 'as' keyword? I just found out!
.center-window-container {
background: wal.$background;
border-radius: 18px;
padding: 12px;
& .left {
.top {
.time {
font-size: 22px;
font-weight: 800;
}
.date {
font-size: 14px;
font-weight: 500;
color: funs.toRGB(color.adjust($color: wal.$foreground, $lightness: -15%));
}
}
}
& .calendar-box {
padding: 5px;
& calendar {
border-radius: 6px;
padding: 2px;
&.view {
background: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -35%));
& header {
background: funs.toRGB(color.adjust($color: wal.$background, $lightness: -20%));
}
}
}
}
}
+12
View File
@@ -0,0 +1,12 @@
@use "sass:color";
@use "./wal";
@use "./functions" as funs;
$bg-primary: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -35%));
$bg-secondary: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -16%));
$bg-tertiary: funs.toRGB(color.adjust($color: $bg-secondary, $lightness: 10%));
$bg-light: wal.$foreground;
$bg-translucent: funs.toRGB(color.change($color: $bg-primary, $alpha: 72%));
$fg-primary: wal.$foreground;
$fg-light: $bg-primary;
$fg-disabled: funs.toRGB(color.adjust($color: wal.$foreground, $lightness: -11%));
+21 -7
View File
@@ -1,5 +1,6 @@
@use "sass:color"; @use "sass:color";
@use "./wal"; @use "./wal";
@use "./functions" as funs;
.control-center-container { .control-center-container {
background: rgba(wal.$background, .65); background: rgba(wal.$background, .65);
@@ -29,7 +30,11 @@
& .button-row { & .button-row {
& button { & button {
padding: 4px 6px; padding: 7px;
margin: {
top: 2px;
bottom: 2px;
};
} }
} }
} }
@@ -49,20 +54,29 @@
} }
} }
icon { .icon.nf {
background-size: 48px; margin-right: 8px;
font-size: 15px;
} }
trough { trough {
background: color.adjust($color: wal.$color1, $lightness: -20%); background: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -20%));
min-height: .8em;
border-radius: 8px; border-radius: 8px;
} }
trough highlight { trough highlight {
background: wal.$color1; background: wal.$color1;
min-height: inherit; border-top-left-radius: inherit;
border-radius: inherit; border-bottom-left-radius: inherit;
}
trough slider {
min-width: 1.2em;
min-height: 1.2em;
border-radius: 50%;
margin: -3px 0;
background: wal.$foreground;
margin-left: -1px;
} }
} }
} }
+14
View File
@@ -0,0 +1,14 @@
@use "sass:color";
/**
* GTK3 only supports sRGB color space, unfortunatly
*/
@function toRGB($color) {
@return rgba(
color.channel($color, "red"),
color.channel($color, "green"),
color.channel($color, "blue"),
color.alpha($color)
);
}
+74 -1
View File
@@ -1,8 +1,81 @@
@use "sass:color"; @use "sass:color";
@use "./wal"; @use "./wal";
@use "./colors";
@use "./functions" as funs;
@mixin reset-props { @mixin reset-props {
all: unset; all: unset;
transition: 120ms linear; transition: 120ms linear;
color: color.adjust($color: wal.$foreground, $lightness: -15%); font-family: "Cantarell", "Noto Sans",
"Noto Sans CJK JP", "Noto Sans CJK KR",
"Noto Sans CJK HK", "Noto Sans CJK SC",
"Noto Sans CJK TC", sans-serif,
"Symbols Nerd Font Mono";
color: colors.$fg-primary;
}
@mixin default-styles {
.button-row {
& > button {
background: colors.$bg-secondary;
margin: 0 1px;
padding: 0 6px;
border-radius: 2px;
&:hover {
background: colors.$bg-tertiary;
}
&:first-child {
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
}
&:last-child {
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
}
}
label.nf,
button.nf label {
font-size: 12px;
font-family: "Symbols Nerd Font Mono", "Noto Sans Nerd Font Mono",
"0xProto Nerd Font Mono", "Fira Code Nerd Font Mono",
"Symbols Nerd Font", "Noto Sans Nerd Font", "Fira Code Nerd Font",
"Font Awesome";
}
& menu {
padding: 4px;
background: wal.$background;
border-radius: 14px;
& separator {
margin: 0 4px;
color: wal.$background;
}
& menuitem {
padding: 8px 16px;
border-radius: 10px;
font-size: 12px;
font-weight: 600;
&:hover {
background: wal.$color1;
}
}
}
& tooltip {
padding: 8px;
border-radius: 14px;
& label {
font-size: 14px;
color: colors.$fg-primary;
}
}
} }
+3 -2
View File
@@ -1,8 +1,9 @@
@use "sass:color"; @use "sass:color";
@use "./wal"; @use "./wal";
@use "./functions" as funs;
.osd { .osd {
background: color.change($color: wal.$background, $alpha: 65%); background: funs.toRGB(color.change($color: wal.$background, $alpha: 65%));
padding: 14px 16px; padding: 14px 16px;
border-radius: 20px; border-radius: 20px;
@@ -23,7 +24,7 @@
levelbar { levelbar {
trough block { trough block {
border-radius: 2px; border-radius: 2px;
background: color.adjust($color: wal.$color1, $lightness: -36%); background: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -36%));
&.empty { &.empty {
border-radius: 2px; border-radius: 2px;
+6 -7
View File
@@ -21,11 +21,11 @@ export function Audio() {
child: new Widget.Box({ child: new Widget.Box({
children: [ children: [
new Widget.Label({ new Widget.Label({
className: "icon nf", className: "nf",
label: "󰕾" label: "󰕾"
} as Widget.LabelProps), } as Widget.LabelProps),
new Widget.Label({ new Widget.Label({
className: "icon nf", className: "volume",
label: bind(Wireplumber.getDefault().getDefaultSink(), "volume").as((volume: number) => label: bind(Wireplumber.getDefault().getDefaultSink(), "volume").as((volume: number) =>
Math.floor(volume * 100) + "%") Math.floor(volume * 100) + "%")
} as Widget.LabelProps) } as Widget.LabelProps)
@@ -42,22 +42,21 @@ export function Audio() {
child: new Widget.Box({ child: new Widget.Box({
children: [ children: [
new Widget.Label({ new Widget.Label({
className: "icon", className: "nf",
label: "󰍬" label: "󰍬"
} as Widget.LabelProps), } as Widget.LabelProps),
new Widget.Label({ new Widget.Label({
className: "volume",
label: bind(Wireplumber.getDefault().getDefaultSource(), "volume").as((volume: number) => label: bind(Wireplumber.getDefault().getDefaultSource(), "volume").as((volume: number) =>
Math.floor(volume * 100) + "%") Math.floor(volume * 100) + "%")
} as Widget.LabelProps) } as Widget.LabelProps)
] ]
}) })
} as Widget.EventBoxProps), } as Widget.EventBoxProps),
new Widget.Box({ new Widget.Label({
className: "notification-bell", className: "bell nf",
child: new Widget.Label({
label: "󰂚" label: "󰂚"
} as Widget.LabelProps) } as Widget.LabelProps)
} as Widget.BoxProps)
] ]
} as Widget.BoxProps) } as Widget.BoxProps)
} as Widget.EventBoxProps); } as Widget.EventBoxProps);
+2 -2
View File
@@ -17,13 +17,13 @@ export function FocusedClient() {
(getAppIcon(client.initialClass) || client.initialClass) (getAppIcon(client.initialClass) || client.initialClass)
: :
"image-missing" "image-missing"
), )
iconSize: Gtk.IconSize.SMALL_TOOLBAR
}), }),
new Widget.Box({ new Widget.Box({
className: "text-content", className: "text-content",
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
homogeneous: false, homogeneous: false,
valign: Gtk.Align.CENTER,
children: [ children: [
new Widget.Label({ new Widget.Label({
className: "class", className: "class",
+2 -1
View File
@@ -7,7 +7,8 @@ export function Logo() {
//tooltipText: tr("bar.logo.tooltip"), //tooltipText: tr("bar.logo.tooltip"),
child: new Widget.Button({ child: new Widget.Button({
onClick: () => AstalHyprland.get_default().dispatch("exec", "anyrun"), onClick: () => AstalHyprland.get_default().dispatch("exec", "anyrun"),
label: "" className: "nf",
label: "",
} as Widget.ButtonProps) } as Widget.ButtonProps)
} as Widget.BoxProps); } as Widget.BoxProps);
} }
+15 -11
View File
@@ -1,4 +1,4 @@
import { bind, Process } from "astal"; import { bind, GLib, Process } from "astal";
import { Gtk, Widget } from "astal/gtk3"; import { Gtk, Widget } from "astal/gtk3";
import AstalMpris from "gi://AstalMpris"; import AstalMpris from "gi://AstalMpris";
import { Separator, SeparatorProps } from "../Separator"; import { Separator, SeparatorProps } from "../Separator";
@@ -19,25 +19,29 @@ export function Media(): Gtk.Widget {
transitionDuration: 260, transitionDuration: 260,
revealChild: false, revealChild: false,
child: new Widget.Box({ child: new Widget.Box({
className: "media-controls", className: "media-controls button-row",
expand: false, expand: false,
homogeneous: false, homogeneous: false,
children: bind(mpris, "players").as((players: Array<AstalMpris.Player>) => children: bind(mpris, "players").as((players: Array<AstalMpris.Player>) =>
players[0] ? [ players[0] ? [
new Widget.Button({ new Widget.Button({
className: "link", className: "link nf",
label: "󰌷", label: "󰌹",
visible: bind(players[0], "metadata").as(metadata => tooltipText: "Copy link to Clipboard",
metadata?.["xesam:url"] ? true : false), visible: bind(players[0], "metadata").as((_metadata: GLib.HashTable) =>
onClick: () => Process.exec(`echo ${players[0].metadata.url}"`) players[0].get_meta("xesam:url") === null),
onClick: () => Process.exec(`wl-copy ${players[0].get_meta("xesam:url")?.get_string()[0]}`)
} as Widget.ButtonProps), } as Widget.ButtonProps),
new Widget.Button({ new Widget.Button({
className: "previous", className: "previous nf",
label: "󰒮", label: "󰒮",
tooltipText: "Previous",
onClick: () => players[0].canGoPrevious && players[0].previous() onClick: () => players[0].canGoPrevious && players[0].previous()
} as Widget.ButtonProps), } as Widget.ButtonProps),
new Widget.Button({ new Widget.Button({
className: "pause", className: "pause nf",
tooltipText: bind(players[0], "playback_status").as((status: AstalMpris.PlaybackStatus) =>
status === AstalMpris.PlaybackStatus.PLAYING ? "Pause" : "Play"),
label: bind(players[0], "playbackStatus").as((status: AstalMpris.PlaybackStatus) => label: bind(players[0], "playbackStatus").as((status: AstalMpris.PlaybackStatus) =>
status === AstalMpris.PlaybackStatus.PLAYING ? "󰏤" : "󰐊"), status === AstalMpris.PlaybackStatus.PLAYING ? "󰏤" : "󰐊"),
onClick: () => { onClick: () => {
@@ -48,7 +52,7 @@ export function Media(): Gtk.Widget {
} }
} as Widget.ButtonProps), } as Widget.ButtonProps),
new Widget.Button({ new Widget.Button({
className: "next", className: "next nf",
label: "󰒭", label: "󰒭",
onClick: () => players[0].canGoNext && players[0].next() onClick: () => players[0].canGoNext && players[0].next()
} as Widget.ButtonProps) } as Widget.ButtonProps)
@@ -69,7 +73,7 @@ export function Media(): Gtk.Widget {
children: bind(mpris, "players").as((players: Array<AstalMpris.Player>) => children: bind(mpris, "players").as((players: Array<AstalMpris.Player>) =>
players[0] ? [ players[0] ? [
new Widget.Label({ new Widget.Label({
className: "icon", className: "player-icon nf",
label: bind(players[0], "busName").as((busName: string) => { label: bind(players[0], "busName").as((busName: string) => {
const playerName: string = busName.split('.')[busName.split('.').length-1]; const playerName: string = busName.split('.')[busName.split('.').length-1];
return playerIcons[playerName as keyof typeof playerIcons] || "󰎇"; return playerIcons[playerName as keyof typeof playerIcons] || "󰎇";
+2 -2
View File
@@ -1,4 +1,4 @@
import { bind } from "astal"; import { bind, Gio } from "astal";
import { Gtk, Widget } from "astal/gtk3"; import { Gtk, Widget } from "astal/gtk3";
import AstalTray from "gi://AstalTray" import AstalTray from "gi://AstalTray"
@@ -19,7 +19,7 @@ export function Tray() {
direction: Gtk.ArrowType.DOWN, direction: Gtk.ArrowType.DOWN,
halign: Gtk.Align.CENTER, halign: Gtk.Align.CENTER,
child: new Widget.Icon({ child: new Widget.Icon({
gIcon: bind(item, "gicon"), gicon: bind(item, "gicon"),
iconSize: Gtk.IconSize.SMALL_TOOLBAR iconSize: Gtk.IconSize.SMALL_TOOLBAR
}) })
} as Widget.MenuButtonProps) } as Widget.MenuButtonProps)
+6
View File
@@ -0,0 +1,6 @@
import { Gtk, Widget } from "astal/gtk3";
export const BigMedia: Gtk.Widget = new Widget.Box({
className: "big-media",
//TODO
} as Widget.BoxProps);
@@ -0,0 +1,73 @@
import { bind } from "astal";
import { Gtk, Widget } from "astal/gtk3";
import AstalNotifd from "gi://AstalNotifd";
import { Notifications } from "../../scripts/notification-handler";
export const NotificationHistory: Gtk.Widget = new Widget.Scrollable({
hscroll: Gtk.PolicyType.NEVER,
vscroll: Gtk.PolicyType.AUTOMATIC,
child: new Widget.Box({
className: "notifications",
children: bind(Notifications, "notificationHistory").as((history: Array<AstalNotifd.Notification>) =>
history && history.length > 0 && history.map((notification: AstalNotifd.Notification) =>
new Widget.Box({
className: "notification",
hexpand: true,
orientation: Gtk.Orientation.VERTICAL,
children: [
new Widget.Box({
className: "top",
expand: true,
children: [
new Widget.Box({
className: "app",
children: [
new Widget.Icon({
icon: notification.appIcon || notification.appName.toLowerCase(),
iconSize: Gtk.IconSize.LARGE_TOOLBAR
}),
new Widget.Label({
className: "name",
label: notification.appName || "Unknown"
} as Widget.LabelProps)
]
} as Widget.BoxProps),
new Widget.Button({
className: "remove",
label: "󱎘",
onClick: () => Notifications.removeFromNotificationHistory(notification.id)
} as Widget.ButtonProps)
]
} as Widget.BoxProps),
new Widget.Box({
className: "content",
expand: true,
children: [
new Widget.Box({
className: "image",
visible: notification.image !== "",
css: `.image { background-image: url('${notification.image}') }`
} as Widget.BoxProps),
new Widget.Box({
orientation: Gtk.Orientation.VERTICAL,
children: [
new Widget.Label({
className: "summary",
useMarkup: true,
label: notification.summary
} as Widget.LabelProps),
new Widget.Label({
className: "body",
useMarkup: true,
label: notification.body
} as Widget.LabelProps)
]
} as Widget.BoxProps)
]
} as Widget.BoxProps)
]
} as Widget.BoxProps)
)
)
} as Widget.BoxProps)
} as Widget.ScrollableProps)
@@ -10,6 +10,7 @@ const uptime = new Variable<string>("Just turned on")
function LockButton(): Widget.Button { function LockButton(): Widget.Button {
return new Widget.Button({ return new Widget.Button({
className: "nf",
label: "󰌾", label: "󰌾",
onClick: () => AstalHyprland.get_default().dispatch("exec", "hyprlock") onClick: () => AstalHyprland.get_default().dispatch("exec", "hyprlock")
} as Widget.ButtonProps) } as Widget.ButtonProps)
@@ -17,6 +18,7 @@ function LockButton(): Widget.Button {
function ColorPickerButton(): Widget.Button { function ColorPickerButton(): Widget.Button {
return new Widget.Button({ return new Widget.Button({
className: "nf",
label: "󰴱", label: "󰴱",
onClick: () => AstalHyprland.get_default().dispatch( onClick: () => AstalHyprland.get_default().dispatch(
"exec", "exec",
@@ -27,6 +29,7 @@ function ColorPickerButton(): Widget.Button {
function ScreenshotButton(): Widget.Button { function ScreenshotButton(): Widget.Button {
return new Widget.Button({ return new Widget.Button({
className: "nf",
label: "󰹑", label: "󰹑",
onClick: () => Process.exec_async( onClick: () => Process.exec_async(
"bash -c 'hyprshot -m region -o $HOME/Screenshots'", "bash -c 'hyprshot -m region -o $HOME/Screenshots'",
@@ -37,6 +40,7 @@ function ScreenshotButton(): Widget.Button {
function SelectWallpaperButton(): Widget.Button { function SelectWallpaperButton(): Widget.Button {
return new Widget.Button({ return new Widget.Button({
className: "nf",
label: "󰸉", label: "󰸉",
onClick: () => Process.exec_async( onClick: () => Process.exec_async(
"bash -c 'sh $HOME/.config/hypr/scripts/change-wallpaper.sh'", "bash -c 'sh $HOME/.config/hypr/scripts/change-wallpaper.sh'",
@@ -47,6 +51,7 @@ function SelectWallpaperButton(): Widget.Button {
function LogoutButton(): Widget.Button { function LogoutButton(): Widget.Button {
return new Widget.Button({ return new Widget.Button({
className: "nf",
label: "󰗽", label: "󰗽",
onClick: () => Process.exec_async( onClick: () => Process.exec_async(
"bash -c 'wlogout -b 5'", "bash -c 'wlogout -b 5'",
+12 -6
View File
@@ -10,9 +10,10 @@ export const Sliders: Gtk.Widget = new Widget.Box({
new Widget.Box({ new Widget.Box({
className: "sink speaker", className: "sink speaker",
children: [ children: [
new Widget.Icon({ new Widget.Label({
icon: "audio-volume-high-symbolic" className: "nf icon",
} as Widget.IconProps), label: "󰕾"
} as Widget.LabelProps),
new Widget.Slider({ new Widget.Slider({
drawValue: false, drawValue: false,
hexpand: true, hexpand: true,
@@ -26,9 +27,10 @@ export const Sliders: Gtk.Widget = new Widget.Box({
new Widget.Box({ new Widget.Box({
className: "source microphone", className: "source microphone",
children: [ children: [
new Widget.Icon({ new Widget.Label({
icon: "microphone-sensitivity-high-symbolic" className: "nf icon",
} as Widget.IconProps), label: "󰍬"
} as Widget.LabelProps),
new Widget.Slider({ new Widget.Slider({
drawValue: false, drawValue: false,
hexpand: true, hexpand: true,
@@ -42,6 +44,10 @@ export const Sliders: Gtk.Widget = new Widget.Box({
/*new Widget.Box({ /*new Widget.Box({
className: "brightness screen", className: "brightness screen",
children: [ children: [
new Widget.Label({
className: "icon nf",
label: "󰃠"
} as Widget.LabelProps),
new Widget.Slider({ new Widget.Slider({
drawValue: false, drawValue: false,
hexpand: true, hexpand: true,
+1
View File
@@ -5,6 +5,7 @@ export const tileList: Array<Gtk.Widget> = [
export const Tiles: Widget.Box = new Widget.Box({ export const Tiles: Widget.Box = new Widget.Box({
child: new Gtk.Grid({ child: new Gtk.Grid({
visible: true,
orientation: Gtk.Orientation.HORIZONTAL, orientation: Gtk.Orientation.HORIZONTAL,
rowHomogeneous: true rowHomogeneous: true
} as Gtk.Grid.ConstructorProps) } as Gtk.Grid.ConstructorProps)
+5 -4
View File
@@ -3,7 +3,6 @@ import { GLib } from "astal";
import { getDateTime } from "../scripts/time"; import { getDateTime } from "../scripts/time";
export const CenterWindow: Widget.Window = new Widget.Window({ export const CenterWindow: Widget.Window = new Widget.Window({
className: "center-window", className: "center-window",
namespace: "center-window", namespace: "center-window",
@@ -12,7 +11,8 @@ export const CenterWindow: Widget.Window = new Widget.Window({
layer: Astal.Layer.OVERLAY, layer: Astal.Layer.OVERLAY,
exclusivity: Astal.Exclusivity.NORMAL, exclusivity: Astal.Exclusivity.NORMAL,
visible: false, visible: false,
height_request: 600, height_request: 400,
margin_top: 10,
anchor: Astal.WindowAnchor.TOP, anchor: Astal.WindowAnchor.TOP,
child: new Widget.Box({ child: new Widget.Box({
className: "center-window-container", className: "center-window-container",
@@ -23,7 +23,7 @@ export const CenterWindow: Widget.Window = new Widget.Window({
width_request: 300, width_request: 300,
children: [ children: [
new Widget.Box({ new Widget.Box({
className: "top time date", className: "top",
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
children: [ children: [
new Widget.Label({ new Widget.Label({
@@ -37,7 +37,7 @@ export const CenterWindow: Widget.Window = new Widget.Window({
dateTime.format("%A, %B %d %Y")) dateTime.format("%A, %B %d %Y"))
} as Widget.LabelProps) } as Widget.LabelProps)
] ]
} as Widget.BoxProps) } as Widget.BoxProps),
] ]
} as Widget.BoxProps), } as Widget.BoxProps),
new Widget.Box({ new Widget.Box({
@@ -46,6 +46,7 @@ export const CenterWindow: Widget.Window = new Widget.Window({
new Widget.Box({ new Widget.Box({
className: "calendar-box", className: "calendar-box",
child: new Gtk.Calendar({ child: new Gtk.Calendar({
visible: true,
show_heading: true, show_heading: true,
show_day_names: true, show_day_names: true,
show_week_numbers: false show_week_numbers: false
+1 -1
View File
@@ -20,7 +20,7 @@ export const ControlCenter: Widget.Window = new Widget.Window({
layer: Astal.Layer.OVERLAY, layer: Astal.Layer.OVERLAY,
margin_top: 10, margin_top: 10,
margin_right: 10, margin_right: 10,
width_request: 450, width_request: 400,
monitor: 0, monitor: 0,
visible: false visible: false
} as Widget.WindowProps, widgetsContainer); } as Widget.WindowProps, widgetsContainer);
+37 -7
View File
@@ -1,26 +1,29 @@
import { Astal, Gtk, Widget } from "astal/gtk3"; import { Astal, Gtk, Widget } from "astal/gtk3";
import { getNotifd, notifications, removeNotification } from "../scripts/notification-handler";
import AstalNotifd from "gi://AstalNotifd"; import AstalNotifd from "gi://AstalNotifd";
import { bind } from "astal"; import { bind } from "astal";
import { Notifications } from "../scripts/notification-handler";
export const FloatingNotifications: Widget.Window = new Widget.Window({ export const FloatingNotifications: Widget.Window = new Widget.Window({
className: "floating-notifications",
namespace: "floating-notifications", namespace: "floating-notifications",
canFocus: false, canFocus: false,
anchor: Astal.WindowAnchor.RIGHT, anchor: Astal.WindowAnchor.RIGHT,
monitor: 0, monitor: 0,
layer: Astal.Layer.OVERLAY, layer: Astal.Layer.OVERLAY,
visible: false, visible: false,
width_request: 350,
exclusivity: Astal.Exclusivity.NORMAL, exclusivity: Astal.Exclusivity.NORMAL,
child: new Widget.Box({ child: new Widget.Box({
className: "notifications", className: "floating-notifications-container",
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
homogeneous: false, homogeneous: false,
children: bind(getNotifd(), "notifications").as(() => { children: bind(Notifications, "notifications").as((notifications: Array<AstalNotifd.Notification>) => {
notifications.length > 0 ? notifications.map((notification: AstalNotifd.Notification) => console.log("something changed!");
return notifications.map((notification: AstalNotifd.Notification) =>
new Widget.Box({ new Widget.Box({
className: "notification", className: "notification",
homogeneous: false, homogeneous: false,
expand: false,
orientation: Gtk.Orientation.VERTICAL,
children: [ children: [
new Widget.Box({ new Widget.Box({
className: "top", className: "top",
@@ -35,13 +38,40 @@ export const FloatingNotifications: Widget.Window = new Widget.Window({
} as Widget.LabelProps), } as Widget.LabelProps),
new Widget.Button({ new Widget.Button({
className: "close-button", className: "close-button",
onClick: () => removeNotification(notification.id) onClick: () => Notifications.removeNotification(notification.id)
} as Widget.ButtonProps) } as Widget.ButtonProps)
] ]
} as Widget.BoxProps),
new Widget.Box({
className: "content",
orientation: Gtk.Orientation.HORIZONTAL,
children: [
new Widget.Box({
className: "image",
visible: notification.image !== "",
css: `.image { background-image: url('${notification.image}'); }`
} as Widget.BoxProps),
new Widget.Box({
className: "text",
orientation: Gtk.Orientation.VERTICAL,
children: [
new Widget.Label({
className: "summary",
useMarkup: true,
label: notification.summary
}),
new Widget.Label({
className: "body",
useMarkup: true,
label: notification.body
} as Widget.LabelProps)
]
} as Widget.BoxProps) } as Widget.BoxProps)
] ]
} as Widget.BoxProps) } as Widget.BoxProps)
) : new Widget.Box({}) ]
} as Widget.BoxProps)
)
}) })
} as Widget.BoxProps) } as Widget.BoxProps)
} as Widget.WindowProps); } as Widget.WindowProps);
+72
View File
@@ -0,0 +1,72 @@
import { Astal, Gdk, Gtk, Widget } from "astal/gtk3";
import { getDateTime } from "../scripts/time";
import { execAsync, GLib, Process } from "astal";
const { TOP, LEFT, RIGHT, BOTTOM } = Astal.WindowAnchor;
export const LogoutMenu: Widget.Window = new Widget.Window({
namespace: "logout-menu",
anchor: TOP | LEFT | RIGHT | BOTTOM,
layer: Astal.Layer.OVERLAY,
exclusivity: Astal.Exclusivity.IGNORE,
monitor: 0,
visible: false,
widthRequest: Gdk.Screen.get_default()?.get_monitor_geometry(0)?.width,
height_request: Gdk.Screen.get_default()?.get_monitor_geometry(0)?.height,
child: new Widget.EventBox({
className: "logout-menu",
onClick: () => Process.exec_async("astal close logout-menu", () => {}),
child: new Widget.Box({
homogeneous: false,
orientation: Gtk.Orientation.VERTICAL,
children: [
new Widget.Box({
className: "top",
expand: true,
orientation: Gtk.Orientation.VERTICAL,
children: [
new Widget.Label({
className: "time",
label: getDateTime().as((dateTime: GLib.DateTime) =>
dateTime.format("%H:%M"))
} as Widget.LabelProps),
new Widget.Label({
className: "date",
label: getDateTime().as((dateTime: GLib.DateTime) =>
dateTime.format("%A, %B %d %Y"))
} as Widget.LabelProps)
]
} as Widget.BoxProps),
new Widget.Box({
className: "button-row",
homogeneous: true,
expand: true,
valign: Gtk.Align.CENTER,
children: [
new Widget.Button({
className: "poweroff nf",
label: "󰐥",
onClick: "ask user if it's fr!"
} as Widget.ButtonProps),
new Widget.Button({
className: "reboot nf",
label: "󰜉",
onClick: "ask user if it's fr!"
} as Widget.ButtonProps),
new Widget.Button({
className: "suspend nf",
label: "󰤄",
onClick: "ask user if it's fr!"
} as Widget.ButtonProps),
new Widget.Button({
className: "logout nf",
label: "󰗽",
onClick: () => execAsync("astal close logout-menu && bash -c 'loginctl terminate-user $USER'")
} as Widget.ButtonProps),
]
} as Widget.BoxProps)
]
})
} as Widget.EventBoxProps)
} as Widget.WindowProps);
+2 -1
View File
@@ -6,6 +6,7 @@ import { ControlCenter } from "./window/ControlCenter";
import { CenterWindow } from "./window/CenterWindow"; import { CenterWindow } from "./window/CenterWindow";
import { FloatingNotifications } from "./window/FloatingNotifications"; import { FloatingNotifications } from "./window/FloatingNotifications";
import { GObject } from "astal"; import { GObject } from "astal";
import { LogoutMenu } from "./window/LogoutMenu";
/** /**
* get open windows / interact with windows(e.g.: close, open or toggle) * get open windows / interact with windows(e.g.: close, open or toggle)
@@ -20,7 +21,7 @@ export const Windows = GObject.registerClass({
WindowsClass.windowsMap.set("osd", OSD); WindowsClass.windowsMap.set("osd", OSD);
WindowsClass.windowsMap.set("control-center", ControlCenter); WindowsClass.windowsMap.set("control-center", ControlCenter);
WindowsClass.windowsMap.set("center-window", CenterWindow); WindowsClass.windowsMap.set("center-window", CenterWindow);
WindowsClass.windowsMap.set("floating-notifications", FloatingNotifications); WindowsClass.windowsMap.set("logout-menu", LogoutMenu);
} }
public _init(...args: any[]) { public _init(...args: any[]) {