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", () =>
!Windows.isVisible(ControlCenter) && triggerOSD(OSDModes.SINK));
}
});
+1 -1
View File
@@ -19,7 +19,7 @@ export function handleArguments(request: string): any {
return handleVolumeArgs(args);
case "reload":
restartInstance({ log: false, instanceName: "astal" });
restartInstance();
return "Reloading instance..."
default:
+69 -35
View File
@@ -1,20 +1,45 @@
import AstalNotifd from "gi://AstalNotifd";
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({
ignoreTimeout: false,
@register()
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
});
} as AstalNotifd.Notifd.ConstructorProps);
export let notifications: Array<AstalNotifd.Notification> = getNotifd().notifications;
export let notificationHistory: Array<AstalNotifd.Notification> = [];
this.getNotifd().connect("notified", (_source: AstalNotifd.Notifd, id: number, _replaced: boolean) => {
this.addNotification(this.getNotifd().get_notification(id));
});
}
notifd.connect("notified", (_source: AstalNotifd.Notifd, id: number, _replaced: boolean) => {
addNotification(getNotifd().get_notification(id));
});
function addNotification(notification: AstalNotifd.Notification) {
prependArray(notifications, getNotifd().get_notification(notification.id));
public addNotification(notification: AstalNotifd.Notification) {
this.prependArray(this.notifications, this.getNotifd().get_notification(notification.id));
// default timeout if undefined
let notificationTimeout = 4000;
@@ -28,36 +53,45 @@ function addNotification(notification: AstalNotifd.Notification) {
break;
}
notification.urgency !== AstalNotifd.Urgency.CRITICAL && timeout(notificationTimeout, () => {
notificationTimeout--;
if(notificationTimeout === 0) {
removeNotification(notification.id);
addToNotificationHistory(notification);
};
});
}
notification.urgency !== AstalNotifd.Urgency.CRITICAL ?
timeout(notificationTimeout, () => {
this.notifications.map((item: AstalNotifd.Notification) =>
item.id === notification.id && (() => {
this.removeNotification(notification.id);
this.addToNotificationHistory(notification);
})())
})
: this.addToNotificationHistory(notification);
export function removeNotification(notificationId: number) {
notifications = notifications.filter((notification: AstalNotifd.Notification) =>
this.emit("notification-added", 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);
}
function addToNotificationHistory(notification: AstalNotifd.Notification) {
prependArray(notificationHistory, notification);
}
this.emit("notification-removed", notificationId);
}
export function removeFromNotificationHistory(notificationId: number) {
notifications = notifications.filter((curNotification: AstalNotifd.Notification) =>
public addToNotificationHistory(notification: AstalNotifd.Notification) {
this.prependArray(this.notificationHistory, notification);
}
public removeFromNotificationHistory(notificationId: number) {
this.notificationHistory = this.notificationHistory.filter((curNotification: AstalNotifd.Notification) =>
curNotification.id !== notificationId);
}
}
function prependArray(array: Array<any>, item: any) {
let tmpArray = array;
tmpArray.reverse();
private prependArray(array: Array<any>, item: any): Array<any> {
let tmpArray = array.reverse();
tmpArray.push(item);
array = tmpArray.reverse();
}
return tmpArray.reverse();
}
export function getNotifd(): AstalNotifd.Notifd {
return notifd;
public getNotifd(): AstalNotifd.Notifd {
return this.notifd;
}
}
+4 -16
View File
@@ -1,30 +1,18 @@
import { monitorFile, Process } from "astal";
import { getUserDirs } from "./user";
import { App } from "astal/gtk3";
const monitoringPaths = [ "./scripts", "./window", "./app.ts", "env.d.ts" ];
export interface InstanceProps {
instanceName?: string;
log?: boolean;
}
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 restartInstance(instanceName?: string): void {
Process.exec_async(`astal -q ${ instanceName || App.instanceName || "astal" }`, () => {});
Process.exec_async(`ags run`, () => {});
}
export function monitorPaths(): void {
monitoringPaths.map((path: string) => {
monitorFile(
path,
() => restartInstance({
instanceName: App.instanceName || "astal",
log: true
})
() => restartInstance()
)
});
}
+1 -1
View File
@@ -23,7 +23,7 @@ export function reloadStyle(): void {
export function compileStyle(): void {
console.log("[LOG] Compiling sass (stylesheet)");
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 {
+9 -46
View File
@@ -1,55 +1,18 @@
@use "sass:color";
@use "./style/bar";
@use "./style/wal";
@use "./style/mixins";
@use "./style/bar";
@use "./style/osd";
@use "./style/control-center";
@use "./style/center-window";
* {
all: unset;
transition: 120ms linear;
color: color.adjust($color: wal.$foreground, $lightness: 15%);
@include mixins.reset-props;
}
.button-row {
& > button {
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;
}
}
window * {
@include mixins.default-styles;
}
+66 -61
View File
@@ -1,39 +1,31 @@
@use "sass:color";
@use "./wal";
@use "./mixins";
@use "./colors";
.bar-container {
@include mixins.reset-props;
@include mixins.default-styles;
padding: 6px;
padding-bottom: 0px;
& {
button {
padding: 6px 8px;
border-radius: 12px;
&:hover {
background: wal.$color1;
}
}
label {
font-size: 12px;
font-family: "Cantarell", "Noto Sans";
font-weight: 500;
}
@include mixins.reset-props;
font-size: 12px;
font-weight: 500;
}
// Style widget groups
& > .bar-centerbox > * {
background: rgba($color: wal.$background, $alpha: .6);
background: colors.$bg-translucent;
padding: 5px;
border-radius: 18px;
// Style widgets
& > *,
& > * > button
& > * {
& > button,
& > eventbox,
& > box {
margin: 0 2px;
&:first-child {
@@ -43,22 +35,33 @@
&:last-child {
margin-right: 0;
}
& > button,
& > eventbox > box {
padding: 4px 8px;
border-radius: 12px;
}
& > button:hover,
& > eventbox:hover > box {
background: colors.$bg-primary;
}
}
}
.workspaces {
@include mixins.reset-props;
padding: 2px 2px;
& button {
all: unset;
border-radius: 16px;
transition: 80ms linear;
padding: 12px 12px;
background: wal.$color1;
background: colors.$bg-tertiary;
margin: 1px 2px;
&.focus {
background: wal.$foreground;
background: colors.$fg-primary;
padding: 12px 20px;
}
}
@@ -76,58 +79,47 @@
font-size: 9px;
font-family: monospace;
font-weight: 600;
color: color.adjust($color: wal.$foreground, $lightness: -11%);
margin-top: 1px;
color: colors.$fg-disabled;
margin-top: 0px;
}
& > .title {
font-size: 11.5px;
font-size: 12px;
font-weight: 500;
margin-top: -2px;
}
}
}
.logo button {
padding: 0 11px;
padding-right: 16px;
& label {
font-size: 14px;
}
}
.media-eventbox {
& > .media > box {
& > .media {
border-radius: 12px;
background: wal.$color1;
padding: 0 7px;
background: colors.$bg-primary;
padding: 0 8px;
}
& .icon {
margin-right: 6px;
& .nf {
margin-right: 4px;
font-size: 14px;
}
}
&.reveal {
& .media > box {
transition: 50ms linear;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
& .media-controls {
transition: none;
padding-left: 6px;
border-top-right-radius: 12px;
border-bottom-right-radius: 12px;
transition: unset;
background: linear-gradient(to left, color.adjust($color: wal.$color1, $lightness: -15%) 45px, wal.$color1);
background: linear-gradient(to left, colors.$bg-primary 45px, colors.$bg-primary);
& > button {
margin: 0px 1px;
margin: 4px 1px;
border-radius: 4px;
label {
font-size: 8px;
}
&:hover {
background: wal.$color2;
background: colors.$bg-secondary;
}
&:first-child {
@@ -143,6 +135,13 @@
}
}
}
&.reveal {
& .media > box {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
}
@@ -170,26 +169,32 @@
}
.audio {
&:hover > box {
background: wal.$color1;
}
@include mixins.reset-props;
& .notification-bell {
padding-left: 10px;
padding-right: 4px;
&:hover > box {
background: colors.$bg-primary;
}
& > box {
padding: 0 9px;
padding: 0 8px;
border-radius: 12px;
& > * > * {
margin: 0 2px;
}
& .sink .icon {
margin-right: 6px;
& .nf {
margin: {
right: 3px;
left: 2px;
};
font-size: 12px;
}
& .source .icon {
margin-right: 4px;
& .bell {
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 "./wal";
@use "./functions" as funs;
.control-center-container {
background: rgba(wal.$background, .65);
@@ -29,7 +30,11 @@
& .button-row {
& button {
padding: 4px 6px;
padding: 7px;
margin: {
top: 2px;
bottom: 2px;
};
}
}
}
@@ -49,20 +54,29 @@
}
}
icon {
background-size: 48px;
.icon.nf {
margin-right: 8px;
font-size: 15px;
}
trough {
background: color.adjust($color: wal.$color1, $lightness: -20%);
min-height: .8em;
background: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -20%));
border-radius: 8px;
}
trough highlight {
background: wal.$color1;
min-height: inherit;
border-radius: inherit;
border-top-left-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 "./wal";
@use "./colors";
@use "./functions" as funs;
@mixin reset-props {
all: unset;
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 "./wal";
@use "./functions" as funs;
.osd {
background: color.change($color: wal.$background, $alpha: 65%);
background: funs.toRGB(color.change($color: wal.$background, $alpha: 65%));
padding: 14px 16px;
border-radius: 20px;
@@ -23,7 +24,7 @@
levelbar {
trough block {
border-radius: 2px;
background: color.adjust($color: wal.$color1, $lightness: -36%);
background: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -36%));
&.empty {
border-radius: 2px;
+6 -7
View File
@@ -21,11 +21,11 @@ export function Audio() {
child: new Widget.Box({
children: [
new Widget.Label({
className: "icon nf",
className: "nf",
label: "󰕾"
} as Widget.LabelProps),
new Widget.Label({
className: "icon nf",
className: "volume",
label: bind(Wireplumber.getDefault().getDefaultSink(), "volume").as((volume: number) =>
Math.floor(volume * 100) + "%")
} as Widget.LabelProps)
@@ -42,22 +42,21 @@ export function Audio() {
child: new Widget.Box({
children: [
new Widget.Label({
className: "icon",
className: "nf",
label: "󰍬"
} as Widget.LabelProps),
new Widget.Label({
className: "volume",
label: bind(Wireplumber.getDefault().getDefaultSource(), "volume").as((volume: number) =>
Math.floor(volume * 100) + "%")
} as Widget.LabelProps)
]
})
} as Widget.EventBoxProps),
new Widget.Box({
className: "notification-bell",
child: new Widget.Label({
new Widget.Label({
className: "bell nf",
label: "󰂚"
} as Widget.LabelProps)
} as Widget.BoxProps)
]
} as Widget.BoxProps)
} as Widget.EventBoxProps);
+2 -2
View File
@@ -17,13 +17,13 @@ export function FocusedClient() {
(getAppIcon(client.initialClass) || client.initialClass)
:
"image-missing"
),
iconSize: Gtk.IconSize.SMALL_TOOLBAR
)
}),
new Widget.Box({
className: "text-content",
orientation: Gtk.Orientation.VERTICAL,
homogeneous: false,
valign: Gtk.Align.CENTER,
children: [
new Widget.Label({
className: "class",
+2 -1
View File
@@ -7,7 +7,8 @@ export function Logo() {
//tooltipText: tr("bar.logo.tooltip"),
child: new Widget.Button({
onClick: () => AstalHyprland.get_default().dispatch("exec", "anyrun"),
label: ""
className: "nf",
label: "",
} as Widget.ButtonProps)
} 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 AstalMpris from "gi://AstalMpris";
import { Separator, SeparatorProps } from "../Separator";
@@ -19,25 +19,29 @@ export function Media(): Gtk.Widget {
transitionDuration: 260,
revealChild: false,
child: new Widget.Box({
className: "media-controls",
className: "media-controls button-row",
expand: false,
homogeneous: false,
children: bind(mpris, "players").as((players: Array<AstalMpris.Player>) =>
players[0] ? [
new Widget.Button({
className: "link",
label: "󰌷",
visible: bind(players[0], "metadata").as(metadata =>
metadata?.["xesam:url"] ? true : false),
onClick: () => Process.exec(`echo ${players[0].metadata.url}"`)
className: "link nf",
label: "󰌹",
tooltipText: "Copy link to Clipboard",
visible: bind(players[0], "metadata").as((_metadata: GLib.HashTable) =>
players[0].get_meta("xesam:url") === null),
onClick: () => Process.exec(`wl-copy ${players[0].get_meta("xesam:url")?.get_string()[0]}`)
} as Widget.ButtonProps),
new Widget.Button({
className: "previous",
className: "previous nf",
label: "󰒮",
tooltipText: "Previous",
onClick: () => players[0].canGoPrevious && players[0].previous()
} as Widget.ButtonProps),
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) =>
status === AstalMpris.PlaybackStatus.PLAYING ? "󰏤" : "󰐊"),
onClick: () => {
@@ -48,7 +52,7 @@ export function Media(): Gtk.Widget {
}
} as Widget.ButtonProps),
new Widget.Button({
className: "next",
className: "next nf",
label: "󰒭",
onClick: () => players[0].canGoNext && players[0].next()
} as Widget.ButtonProps)
@@ -69,7 +73,7 @@ export function Media(): Gtk.Widget {
children: bind(mpris, "players").as((players: Array<AstalMpris.Player>) =>
players[0] ? [
new Widget.Label({
className: "icon",
className: "player-icon nf",
label: bind(players[0], "busName").as((busName: string) => {
const playerName: string = busName.split('.')[busName.split('.').length-1];
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 AstalTray from "gi://AstalTray"
@@ -19,7 +19,7 @@ export function Tray() {
direction: Gtk.ArrowType.DOWN,
halign: Gtk.Align.CENTER,
child: new Widget.Icon({
gIcon: bind(item, "gicon"),
gicon: bind(item, "gicon"),
iconSize: Gtk.IconSize.SMALL_TOOLBAR
})
} 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 {
return new Widget.Button({
className: "nf",
label: "󰌾",
onClick: () => AstalHyprland.get_default().dispatch("exec", "hyprlock")
} as Widget.ButtonProps)
@@ -17,6 +18,7 @@ function LockButton(): Widget.Button {
function ColorPickerButton(): Widget.Button {
return new Widget.Button({
className: "nf",
label: "󰴱",
onClick: () => AstalHyprland.get_default().dispatch(
"exec",
@@ -27,6 +29,7 @@ function ColorPickerButton(): Widget.Button {
function ScreenshotButton(): Widget.Button {
return new Widget.Button({
className: "nf",
label: "󰹑",
onClick: () => Process.exec_async(
"bash -c 'hyprshot -m region -o $HOME/Screenshots'",
@@ -37,6 +40,7 @@ function ScreenshotButton(): Widget.Button {
function SelectWallpaperButton(): Widget.Button {
return new Widget.Button({
className: "nf",
label: "󰸉",
onClick: () => Process.exec_async(
"bash -c 'sh $HOME/.config/hypr/scripts/change-wallpaper.sh'",
@@ -47,6 +51,7 @@ function SelectWallpaperButton(): Widget.Button {
function LogoutButton(): Widget.Button {
return new Widget.Button({
className: "nf",
label: "󰗽",
onClick: () => Process.exec_async(
"bash -c 'wlogout -b 5'",
+12 -6
View File
@@ -10,9 +10,10 @@ export const Sliders: Gtk.Widget = new Widget.Box({
new Widget.Box({
className: "sink speaker",
children: [
new Widget.Icon({
icon: "audio-volume-high-symbolic"
} as Widget.IconProps),
new Widget.Label({
className: "nf icon",
label: "󰕾"
} as Widget.LabelProps),
new Widget.Slider({
drawValue: false,
hexpand: true,
@@ -26,9 +27,10 @@ export const Sliders: Gtk.Widget = new Widget.Box({
new Widget.Box({
className: "source microphone",
children: [
new Widget.Icon({
icon: "microphone-sensitivity-high-symbolic"
} as Widget.IconProps),
new Widget.Label({
className: "nf icon",
label: "󰍬"
} as Widget.LabelProps),
new Widget.Slider({
drawValue: false,
hexpand: true,
@@ -42,6 +44,10 @@ export const Sliders: Gtk.Widget = new Widget.Box({
/*new Widget.Box({
className: "brightness screen",
children: [
new Widget.Label({
className: "icon nf",
label: "󰃠"
} as Widget.LabelProps),
new Widget.Slider({
drawValue: false,
hexpand: true,
+1
View File
@@ -5,6 +5,7 @@ export const tileList: Array<Gtk.Widget> = [
export const Tiles: Widget.Box = new Widget.Box({
child: new Gtk.Grid({
visible: true,
orientation: Gtk.Orientation.HORIZONTAL,
rowHomogeneous: true
} as Gtk.Grid.ConstructorProps)
+5 -4
View File
@@ -3,7 +3,6 @@ import { GLib } from "astal";
import { getDateTime } from "../scripts/time";
export const CenterWindow: Widget.Window = new Widget.Window({
className: "center-window",
namespace: "center-window",
@@ -12,7 +11,8 @@ export const CenterWindow: Widget.Window = new Widget.Window({
layer: Astal.Layer.OVERLAY,
exclusivity: Astal.Exclusivity.NORMAL,
visible: false,
height_request: 600,
height_request: 400,
margin_top: 10,
anchor: Astal.WindowAnchor.TOP,
child: new Widget.Box({
className: "center-window-container",
@@ -23,7 +23,7 @@ export const CenterWindow: Widget.Window = new Widget.Window({
width_request: 300,
children: [
new Widget.Box({
className: "top time date",
className: "top",
orientation: Gtk.Orientation.VERTICAL,
children: [
new Widget.Label({
@@ -37,7 +37,7 @@ export const CenterWindow: Widget.Window = new Widget.Window({
dateTime.format("%A, %B %d %Y"))
} as Widget.LabelProps)
]
} as Widget.BoxProps)
} as Widget.BoxProps),
]
} as Widget.BoxProps),
new Widget.Box({
@@ -46,6 +46,7 @@ export const CenterWindow: Widget.Window = new Widget.Window({
new Widget.Box({
className: "calendar-box",
child: new Gtk.Calendar({
visible: true,
show_heading: true,
show_day_names: true,
show_week_numbers: false
+1 -1
View File
@@ -20,7 +20,7 @@ export const ControlCenter: Widget.Window = new Widget.Window({
layer: Astal.Layer.OVERLAY,
margin_top: 10,
margin_right: 10,
width_request: 450,
width_request: 400,
monitor: 0,
visible: false
} as Widget.WindowProps, widgetsContainer);
+37 -7
View File
@@ -1,26 +1,29 @@
import { Astal, Gtk, Widget } from "astal/gtk3";
import { getNotifd, notifications, removeNotification } from "../scripts/notification-handler";
import AstalNotifd from "gi://AstalNotifd";
import { bind } from "astal";
import { Notifications } from "../scripts/notification-handler";
export const FloatingNotifications: Widget.Window = new Widget.Window({
className: "floating-notifications",
namespace: "floating-notifications",
canFocus: false,
anchor: Astal.WindowAnchor.RIGHT,
monitor: 0,
layer: Astal.Layer.OVERLAY,
visible: false,
width_request: 350,
exclusivity: Astal.Exclusivity.NORMAL,
child: new Widget.Box({
className: "notifications",
className: "floating-notifications-container",
orientation: Gtk.Orientation.VERTICAL,
homogeneous: false,
children: bind(getNotifd(), "notifications").as(() => {
notifications.length > 0 ? notifications.map((notification: AstalNotifd.Notification) =>
children: bind(Notifications, "notifications").as((notifications: Array<AstalNotifd.Notification>) => {
console.log("something changed!");
return notifications.map((notification: AstalNotifd.Notification) =>
new Widget.Box({
className: "notification",
homogeneous: false,
expand: false,
orientation: Gtk.Orientation.VERTICAL,
children: [
new Widget.Box({
className: "top",
@@ -35,13 +38,40 @@ export const FloatingNotifications: Widget.Window = new Widget.Window({
} as Widget.LabelProps),
new Widget.Button({
className: "close-button",
onClick: () => removeNotification(notification.id)
onClick: () => Notifications.removeNotification(notification.id)
} 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)
) : new Widget.Box({})
]
} as Widget.BoxProps)
)
})
} as Widget.BoxProps)
} 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 { FloatingNotifications } from "./window/FloatingNotifications";
import { GObject } from "astal";
import { LogoutMenu } from "./window/LogoutMenu";
/**
* 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("control-center", ControlCenter);
WindowsClass.windowsMap.set("center-window", CenterWindow);
WindowsClass.windowsMap.set("floating-notifications", FloatingNotifications);
WindowsClass.windowsMap.set("logout-menu", LogoutMenu);
}
public _init(...args: any[]) {