[AGS] GTK4 Migration: Partially complete
This commit is contained in:
parent
7380c75818
commit
8b70f80e60
@ -1,16 +1,16 @@
|
|||||||
import { App } from "astal/gtk3"
|
import { App } from "astal/gtk4"
|
||||||
import style from "./style.scss"
|
import style from "./style.scss"
|
||||||
|
|
||||||
import notifications from "./components/notifications/handler";
|
import notifications from "./components/notifications/handler";
|
||||||
import Bar from "./components/bar/ui/Bar";
|
// import Bar from "./components/bar/ui/Bar";
|
||||||
|
|
||||||
App.start({
|
App.start({
|
||||||
instanceName: "runner",
|
instanceName: "runner",
|
||||||
css: style,
|
css: style,
|
||||||
main() {
|
main() {
|
||||||
notifications.startNotificationHandler( 0, App.get_monitors()[0] );
|
notifications.startNotificationHandler( App.get_monitors()[0] );
|
||||||
// TODO: Monitor handling
|
// TODO: Monitor handling
|
||||||
Bar.Bar( App.get_monitors()[0] );
|
// Bar.Bar( App.get_monitors()[0] );
|
||||||
},
|
},
|
||||||
requestHandler(request, res) {
|
requestHandler(request, res) {
|
||||||
const args = request.trimStart().split( ' ' );
|
const args = request.trimStart().split( ' ' );
|
||||||
@ -19,7 +19,7 @@ App.start({
|
|||||||
if ( args[ 0 ] === 'notifier' ) {
|
if ( args[ 0 ] === 'notifier' ) {
|
||||||
res( notifications.cliHandler( args ) );
|
res( notifications.cliHandler( args ) );
|
||||||
} else if ( args[ 0 ] === 'bar' ) {
|
} else if ( args[ 0 ] === 'bar' ) {
|
||||||
res( Bar.cliHandler( args ) );
|
// res( Bar.cliHandler( args ) );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import AstalTray from "gi://AstalTray";
|
import AstalTray from "gi://AstalTray";
|
||||||
import { bind, Variable } from "astal";
|
import { bind, Variable } from "astal";
|
||||||
import AstalHyprland from "gi://AstalHyprland";
|
import AstalHyprland from "gi://AstalHyprland";
|
||||||
|
import { Gtk } from "astal/gtk4";
|
||||||
|
|
||||||
const SysTray = () => {
|
const SysTray = () => {
|
||||||
const tray = AstalTray.get_default();
|
const tray = AstalTray.get_default();
|
||||||
@ -48,12 +49,12 @@ const ActiveWindow = () => {
|
|||||||
visible.set( !visible.get() );
|
visible.set( !visible.get() );
|
||||||
}
|
}
|
||||||
|
|
||||||
return <box className={"HyprlandFocusedClients"} visible={focused.as(Boolean)}>
|
return <box cssName={"HyprlandFocusedClients"} visible={focused.as(Boolean)}>
|
||||||
<button onClicked={toggleOverlay}>
|
<Gtk.Button onClicked={toggleOverlay}>
|
||||||
{focused.as( client => (
|
{focused.as( client => (
|
||||||
client && <label label={bind( client, "title" ).as( String )} />
|
client && <label label={bind( client, "title" ).as( String )} />
|
||||||
))}
|
))}
|
||||||
</button>
|
</Gtk.Button>
|
||||||
<eventbox visible={bind(visible).as( v => v )} name="popover-container">
|
<eventbox visible={bind(visible).as( v => v )} name="popover-container">
|
||||||
<label label="This is a test"></label>
|
<label label="This is a test"></label>
|
||||||
</eventbox>
|
</eventbox>
|
||||||
|
@ -7,209 +7,267 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Astal, Gtk, Gdk } from "astal/gtk3"
|
import { Astal, Gdk } from "astal/gtk4"
|
||||||
import Notifd from "gi://AstalNotifd";
|
import Notifd from "gi://AstalNotifd";
|
||||||
import Notification from "./notifications";
|
import Notification from "./notifications";
|
||||||
import { type Subscribable } from "astal/binding";
|
import { timeout, Variable } from "astal"
|
||||||
import { Variable, bind, timeout } from "astal"
|
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
// Config
|
// Config
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
const TIMEOUT_DELAY = 5000;
|
const TIMEOUT_DELAY = 5000;
|
||||||
|
let isRunning = false;
|
||||||
|
let notificationMenuOpen = false;
|
||||||
|
|
||||||
class Notifier implements Subscribable {
|
interface NotificationDetails {
|
||||||
private display: Map<number, Gtk.Widget> = new Map();
|
notification: Notifd.Notification;
|
||||||
private notifications: Map<number, Notifd.Notification> = new Map();
|
backendID: number;
|
||||||
|
notifdID: number;
|
||||||
|
}
|
||||||
|
|
||||||
private notifd: Notifd.Notifd;
|
|
||||||
private subscriberData: Variable<Gtk.Widget[]> = Variable( [] );
|
|
||||||
private instanceID: number;
|
|
||||||
private menuOpen: boolean;
|
|
||||||
|
|
||||||
/**
|
// ───────────────────────────────────────────────────────────────────
|
||||||
* Sets up the notifier
|
// ╭───────────────────────────────────────────────╮
|
||||||
|
// │ Handler │
|
||||||
|
// ╰───────────────────────────────────────────────╯
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
|
let ShownNotifications: number[] = [];
|
||||||
|
const ShownNotificationsCount: Variable<number> = Variable( 0 );
|
||||||
|
let Notifications: NotificationDetails[] = [];
|
||||||
|
|
||||||
|
const notifd = Notifd.get_default();
|
||||||
|
notifd.ignoreTimeout = true;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a notification by its internal ID
|
||||||
|
* @param index The notifd ID of the notification
|
||||||
*/
|
*/
|
||||||
constructor( id: number ) {
|
const deleteNotification = ( index: number ): void => {
|
||||||
this.instanceID = id;
|
hideNotification( index );
|
||||||
this.menuOpen = false;
|
Notifications.splice( index, 1 );
|
||||||
this.notifd = Notifd.get_default();
|
}
|
||||||
this.notifd.ignoreTimeout = true;
|
|
||||||
|
|
||||||
this.notifd.connect( 'notified', ( _, id ) => {
|
// ───────────────────────────────────────────────────────────────────
|
||||||
this.add( id );
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a notification by notifd id
|
||||||
|
* @param id The notifd ID of the notification
|
||||||
|
*/
|
||||||
|
const deleteNotificationByNotificationID = ( id: number ): void => {
|
||||||
|
const index = findNotificationByNotificationID( id );
|
||||||
|
if ( index > -1 ) {
|
||||||
|
deleteNotification( index );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the internal ID from the notifd id for a notification (helper function)
|
||||||
|
* @param id The notifd ID of the notification
|
||||||
|
* @returns The internal ID or -1 if not found
|
||||||
|
*/
|
||||||
|
const findNotificationByNotificationID = ( id: number ): number => {
|
||||||
|
// Find index in Notifications array
|
||||||
|
for (let index = 0; index < Notifications.length; index++) {
|
||||||
|
if ( Notifications[ index ].notifdID === id ) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a notification to the notification handler
|
||||||
|
* @param id The notifd ID of the notification
|
||||||
|
*/
|
||||||
|
const addNotification = ( id: number ): void => {
|
||||||
|
print( '[ Notifications ] Notification with id ' + id + ' added.' );
|
||||||
|
const currIndex = Notifications.length;
|
||||||
|
Notifications.push( {
|
||||||
|
notifdID: id,
|
||||||
|
backendID: currIndex,
|
||||||
|
notification: notifd.get_notification( id )
|
||||||
} );
|
} );
|
||||||
|
|
||||||
this.notifd.connect( 'resolved', ( _, id ) => {
|
showNotification( currIndex );
|
||||||
this.delete( id );
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the notifd runner and handle notifications.
|
||||||
|
*/
|
||||||
|
const hookToNotificationDaemon = (): void => {
|
||||||
|
if ( isRunning ) {
|
||||||
|
printerr( '[ Notifications ] Error: Already running' );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isRunning = true;
|
||||||
|
|
||||||
|
notifd.connect( 'notified', ( _, id ) => {
|
||||||
|
addNotification( id );
|
||||||
|
} );
|
||||||
|
|
||||||
|
notifd.connect( 'resolved', ( _, id ) => {
|
||||||
|
deleteNotificationByNotificationID( id );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a notification. It will stay on screen (regardless of removeAgain passed in), if
|
||||||
|
* critical urgency
|
||||||
|
* @param id The internal id (index in Notifications array)
|
||||||
|
* @param removeAgain = true If to remove the notification from the screen again automatically
|
||||||
|
*/
|
||||||
|
const showNotification = ( id: number, removeAgain: boolean = true ) => {
|
||||||
|
// Add notification to UI for display
|
||||||
|
ShownNotifications.reverse().push( id );
|
||||||
|
ShownNotifications.reverse();
|
||||||
|
ShownNotificationsCount.set( ShownNotifications.length );
|
||||||
|
|
||||||
|
// Set delay to remove the notification again
|
||||||
|
if ( removeAgain && Notifications[ id ].notification.get_urgency() !== Notifd.Urgency.CRITICAL ) {
|
||||||
|
timeout( TIMEOUT_DELAY, () => {
|
||||||
|
hideNotification( id );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private notify () {
|
// ───────────────────────────────────────────────────────────────────
|
||||||
this.subscriberData.set( [ ...this.display.values() ].reverse() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private add ( id: number ) {
|
|
||||||
this.notifications.set( id, this.notifd.get_notification( id )! );
|
|
||||||
this.show( id );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show an element on screen
|
* Stop displaying notification
|
||||||
* @param id - The id of the element to be shown
|
* @param id The internal id (index in the Notifications array)
|
||||||
*/
|
*/
|
||||||
private show ( id: number ) {
|
const hideNotification = ( id: number ) => {
|
||||||
this.set( id, Notification( {
|
if ( !notificationMenuOpen ) {
|
||||||
notification: this.notifications.get( id )!,
|
ShownNotifications.splice( ShownNotifications.indexOf( id ), 1 );
|
||||||
onHoverLost: () => {
|
|
||||||
if ( !this.menuOpen ) {
|
|
||||||
this.hide( id );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setup: () => timeout( TIMEOUT_DELAY, () => {
|
|
||||||
if ( !this.menuOpen ) {
|
|
||||||
this.hide( id );
|
|
||||||
}
|
|
||||||
} ),
|
|
||||||
id: id,
|
|
||||||
delete: deleteHelper,
|
|
||||||
instanceID: this.instanceID
|
|
||||||
} ) )
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
// ───────────────────────────────────────────────────────────────────
|
||||||
* Set a selected widget to be shown
|
|
||||||
* @param id - The id of the element to be referenced for later
|
|
||||||
* @param widget - A GTK widget instance
|
/**
|
||||||
|
* Open the notification menu. Called by toggleNotificationMenu too
|
||||||
*/
|
*/
|
||||||
private set ( id: number, widget: Gtk.Widget ) {
|
const openNotificationMenu = () => {
|
||||||
this.display.get( id )?.destroy();
|
// Simply show all notifications
|
||||||
this.display.set( id, widget );
|
notificationMenuOpen = true;
|
||||||
this.notify();
|
const ShownNotifications = [];
|
||||||
|
for (let index = 0; index < Notifications.length; index++) {
|
||||||
|
ShownNotifications.push( index );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
// ───────────────────────────────────────────────────────────────────
|
||||||
* Hide, not delete notification (= send to notification centre)
|
|
||||||
* @param id - The id of the notification to hide
|
|
||||||
|
/**
|
||||||
|
* Close the notification menu. Called by toggleNotificationMenu too
|
||||||
*/
|
*/
|
||||||
private hide ( id: number ) {
|
const closeNotificationMenu = () => {
|
||||||
this.display.get( id )?.destroy();
|
// Hide all notifications
|
||||||
this.display.delete( id );
|
notificationMenuOpen = true;
|
||||||
this.notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
ShownNotifications = [];
|
||||||
* Delete a notification (from notification centre too)
|
ShownNotificationsCount.set( 0 );
|
||||||
* @param id - The id of the notification to hide
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle the notification menu (i.e. show all notifications)
|
||||||
*/
|
*/
|
||||||
delete ( id: number ) {
|
const toggleNotificationMenu = () => {
|
||||||
this.hide( id );
|
if ( notificationMenuOpen ) {
|
||||||
this.notifications.get( id )?.dismiss();
|
closeNotificationMenu();
|
||||||
this.notifications.delete( id );
|
|
||||||
if ( this.notifications.size == 0 ) {
|
|
||||||
this.menuOpen = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
openNotificationMenu () {
|
|
||||||
// Show all notifications that have not been cleared
|
|
||||||
if ( this.notifications.size > 0 ) {
|
|
||||||
this.menuOpen = true;
|
|
||||||
this.notifications.forEach( ( _, id ) => {
|
|
||||||
this.show( id );
|
|
||||||
} )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hideNotifications () {
|
|
||||||
this.menuOpen = false;
|
|
||||||
this.notifications.forEach( ( _, id ) => {
|
|
||||||
this.hide( id );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleNotificationMenu () {
|
|
||||||
if ( this.menuOpen ) {
|
|
||||||
this.hideNotifications();
|
|
||||||
} else {
|
} else {
|
||||||
this.openNotificationMenu();
|
openNotificationMenu();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clearAllNotifications () {
|
|
||||||
this.menuOpen = false;
|
|
||||||
this.notifications.forEach( ( _, id ) => {
|
|
||||||
this.delete( id );
|
|
||||||
} )
|
|
||||||
}
|
|
||||||
|
|
||||||
clearNewestNotification () {
|
|
||||||
this.delete( [ ...this.notifications.keys() ][0] );
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribe(callback: (value: unknown) => void): () => void {
|
|
||||||
return this.subscriberData.subscribe( callback );
|
|
||||||
}
|
|
||||||
|
|
||||||
get() {
|
|
||||||
return this.subscriberData.get();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const notifiers: Map<number, Notifier> = new Map();
|
// ───────────────────────────────────────────────────────────────────
|
||||||
const deleteHelper = ( id: number, instanceID: number ) => {
|
|
||||||
notifiers.get( instanceID )?.delete( id );
|
|
||||||
|
/**
|
||||||
|
* Delete all notifications
|
||||||
|
*/
|
||||||
|
const clearAllNotifications = () => {
|
||||||
|
Notifications = [];
|
||||||
|
ShownNotifications = [];
|
||||||
|
ShownNotificationsCount.set( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
const openNotificationMenu = ( id: number ) => {
|
// ───────────────────────────────────────────────────────────────────
|
||||||
notifiers.get( id )?.openNotificationMenu();
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the newest notifications
|
||||||
|
*/
|
||||||
|
const clearNewestNotifications = () => {
|
||||||
|
ShownNotifications.splice( 0, 1 );
|
||||||
|
|
||||||
|
Notifications.splice( Notifications.length - 1, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeNotificationMenu = ( id: number ) => {
|
|
||||||
notifiers.get( id )?.hideNotifications();
|
|
||||||
}
|
|
||||||
|
|
||||||
const toggleNotificationMenu = ( id: number ) => {
|
|
||||||
notifiers.get( id )?.toggleNotificationMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
const clearAllNotifications = ( id: number ) => {
|
// ───────────────────────────────────────────────────────────────────
|
||||||
notifiers.get( id )?.clearAllNotifications();
|
// ╭───────────────────────────────────────────────╮
|
||||||
}
|
// │ User Interface │
|
||||||
|
// ╰───────────────────────────────────────────────╯
|
||||||
const clearNewestNotifications = ( id: number ) => {
|
// ───────────────────────────────────────────────────────────────────
|
||||||
notifiers.get( id )?.clearNewestNotification();
|
const startNotificationHandler = (gdkmonitor: Gdk.Monitor) => {
|
||||||
}
|
|
||||||
|
|
||||||
const startNotificationHandler = (id: number, gdkmonitor: Gdk.Monitor) => {
|
|
||||||
const { TOP, RIGHT } = Astal.WindowAnchor
|
const { TOP, RIGHT } = Astal.WindowAnchor
|
||||||
const notifier: Notifier = new Notifier( id );
|
|
||||||
notifiers.set( id, notifier );
|
hookToNotificationDaemon();
|
||||||
|
const range = (n: number) => [...Array(n).keys()];
|
||||||
|
|
||||||
return <window
|
return <window
|
||||||
className="NotificationHandler"
|
cssClasses={["NotificationHandler"]}
|
||||||
gdkmonitor={gdkmonitor}
|
gdkmonitor={gdkmonitor}
|
||||||
exclusivity={Astal.Exclusivity.EXCLUSIVE}
|
exclusivity={Astal.Exclusivity.EXCLUSIVE}
|
||||||
anchor={TOP | RIGHT}>
|
anchor={TOP | RIGHT}>
|
||||||
<box vertical noImplicitDestroy>
|
<box vertical noImplicitDestroy>
|
||||||
{bind(notifier)}
|
{ShownNotificationsCount( n => range( n ).map( i => {
|
||||||
|
print( 'Rendering' );
|
||||||
|
// i is index in ShownNotifications array
|
||||||
|
return <Notification id={i} delete={deleteNotification} notification={Notifications[ i ].notification}></Notification>
|
||||||
|
} ) ) }
|
||||||
</box>
|
</box>
|
||||||
</window>
|
</window>
|
||||||
}
|
}
|
||||||
|
|
||||||
const cliHandler = ( args: string[] ): string => {
|
const cliHandler = ( args: string[] ): string => {
|
||||||
if ( args[ 1 ] == 'show' ) {
|
if ( args[ 1 ] == 'show' ) {
|
||||||
openNotificationMenu( 0 );
|
openNotificationMenu();
|
||||||
return 'Showing all open notifications';
|
return 'Showing all open notifications';
|
||||||
} else if ( args[ 1 ] == 'hide' ) {
|
} else if ( args[ 1 ] == 'hide' ) {
|
||||||
closeNotificationMenu( 0 );
|
closeNotificationMenu();
|
||||||
return 'Hid all notifications';
|
return 'Hid all notifications';
|
||||||
} else if ( args[ 1 ] == 'clear' ) {
|
} else if ( args[ 1 ] == 'clear' ) {
|
||||||
clearAllNotifications( 0 );
|
clearAllNotifications();
|
||||||
return 'Cleared all notifications';
|
return 'Cleared all notifications';
|
||||||
} else if ( args[ 1 ] == 'clear-newest' ) {
|
} else if ( args[ 1 ] == 'clear-newest' ) {
|
||||||
clearNewestNotifications( 0 );
|
clearNewestNotifications();
|
||||||
return 'Cleared newest notification';
|
return 'Cleared newest notification';
|
||||||
} else if ( args[ 1 ] == 'toggle' ) {
|
} else if ( args[ 1 ] == 'toggle' ) {
|
||||||
toggleNotificationMenu( 0 );
|
toggleNotificationMenu();
|
||||||
return 'Toggled notifications';
|
return 'Toggled notifications';
|
||||||
} else {
|
} else {
|
||||||
return 'Unknown command!';
|
return 'Unknown command!';
|
||||||
|
@ -9,11 +9,17 @@ $fg-color: #{"@theme_fg_color"};
|
|||||||
$bg-color: #{"@theme_bg_color"};
|
$bg-color: #{"@theme_bg_color"};
|
||||||
$error: red;
|
$error: red;
|
||||||
|
|
||||||
window.NotificationPopups {
|
window.NotificationHandler {
|
||||||
all: unset;
|
all: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
eventbox.Notification {
|
box.Notification {
|
||||||
|
min-width: 400px;
|
||||||
|
border-radius: 13px;
|
||||||
|
background-color: $bg-color;
|
||||||
|
margin: .5rem 1rem .5rem 1rem;
|
||||||
|
box-shadow: 2px 3px 8px 0 gtkalpha(black, .4);
|
||||||
|
border: 1pt solid gtkalpha($fg-color, .03);
|
||||||
|
|
||||||
&:first-child>box {
|
&:first-child>box {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
@ -23,16 +29,6 @@ eventbox.Notification {
|
|||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eventboxes can not take margins so we style its inner box instead
|
|
||||||
>box {
|
|
||||||
min-width: 400px;
|
|
||||||
border-radius: 13px;
|
|
||||||
background-color: $bg-color;
|
|
||||||
margin: .5rem 1rem .5rem 1rem;
|
|
||||||
box-shadow: 2px 3px 8px 0 gtkalpha(black, .4);
|
|
||||||
border: 1pt solid gtkalpha($fg-color, .03);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.critical>box {
|
&.critical>box {
|
||||||
border: 1pt solid gtkalpha($error, .4);
|
border: 1pt solid gtkalpha($error, .4);
|
||||||
|
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
// From astal examples
|
// From astal examples
|
||||||
|
|
||||||
import { GLib } from "astal"
|
import { GLib } from "astal"
|
||||||
import { Gtk, Astal } from "astal/gtk3"
|
import { Gtk } from "astal/gtk4"
|
||||||
import { type EventBox } from "astal/gtk3/widget"
|
|
||||||
import Notifd from "gi://AstalNotifd"
|
import Notifd from "gi://AstalNotifd"
|
||||||
|
// import Pango from "gi://Pango?version=1.0"
|
||||||
const isIcon = (icon: string) =>
|
|
||||||
!!Astal.Icon.lookup_icon(icon)
|
|
||||||
|
|
||||||
const fileExists = (path: string) =>
|
const fileExists = (path: string) =>
|
||||||
GLib.file_test(path, GLib.FileTest.EXISTS)
|
GLib.file_test(path, GLib.FileTest.EXISTS)
|
||||||
@ -27,78 +24,73 @@ const urgency = (n: Notifd.Notification) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
delete( id: number, instanceID: number ): void
|
delete( id: number ): void
|
||||||
setup(self: EventBox): void
|
|
||||||
onHoverLost(self: EventBox): void
|
|
||||||
notification: Notifd.Notification
|
notification: Notifd.Notification
|
||||||
id: number
|
id: number
|
||||||
instanceID: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Notification(props: Props) {
|
export default function Notification(props: Props) {
|
||||||
const { notification: n, onHoverLost, setup, id: id, delete: del, instanceID: instance } = props
|
const { notification: n, id: id, delete: del } = props
|
||||||
const { START, CENTER, END } = Gtk.Align
|
const { START, CENTER, END } = Gtk.Align
|
||||||
|
|
||||||
return <eventbox
|
return <box vertical
|
||||||
className={`Notification ${urgency(n)}`}
|
cssClasses={['Notification', urgency(n)]}>
|
||||||
setup={setup}
|
<box cssName="header">
|
||||||
onHoverLost={onHoverLost}>
|
{(n.appIcon || n.desktopEntry) ? <Gtk.Image
|
||||||
<box vertical>
|
cssName="app-icon"
|
||||||
<box className="header">
|
|
||||||
{(n.appIcon || n.desktopEntry) && <icon
|
|
||||||
className="app-icon"
|
|
||||||
visible={Boolean(n.appIcon || n.desktopEntry)}
|
visible={Boolean(n.appIcon || n.desktopEntry)}
|
||||||
icon={n.appIcon || n.desktopEntry}
|
iconName={n.appIcon || n.desktopEntry}
|
||||||
/>}
|
/> : <Gtk.Image iconName={'window-close-symbolic'}></Gtk.Image>}
|
||||||
<label
|
<label
|
||||||
className="app-name"
|
cssName="app-name"
|
||||||
halign={START}
|
halign={START}
|
||||||
truncate
|
// ellipsize={Pango.EllipsizeMode.END}
|
||||||
label={n.appName || "Unknown"}
|
label={n.appName || "Unknown"}
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
className="time"
|
cssName="time"
|
||||||
hexpand
|
hexpand
|
||||||
halign={END}
|
halign={END}
|
||||||
label={time(n.time)}
|
label={time(n.time)}
|
||||||
/>
|
/>
|
||||||
<button onClicked={() => del( id, instance )}>
|
<button onClicked={() => del( id )}>
|
||||||
<icon icon="window-close-symbolic" />
|
<Gtk.Image iconName="window-close-symbolic" />
|
||||||
</button>
|
</button>
|
||||||
</box>
|
</box>
|
||||||
<Gtk.Separator visible />
|
<Gtk.Separator visible />
|
||||||
<box className="content">
|
<box cssName="content">
|
||||||
{n.image && fileExists(n.image) && <box
|
{n.image && fileExists(n.image) ? <box
|
||||||
valign={START}
|
valign={START}
|
||||||
className="image"
|
cssName="image">
|
||||||
css={`background-image: url('${n.image}')`}
|
<Gtk.Image file={n.image}></Gtk.Image>
|
||||||
/>}
|
</box>
|
||||||
{n.image && isIcon(n.image) && <box
|
: <box></box>}
|
||||||
|
{n.image ? <box
|
||||||
expand={false}
|
expand={false}
|
||||||
valign={START}
|
valign={START}
|
||||||
className="icon-image">
|
className="icon-image">
|
||||||
<icon icon={n.image} expand halign={CENTER} valign={CENTER} />
|
<Gtk.Image iconName={n.image} expand halign={CENTER} valign={CENTER} />
|
||||||
</box>}
|
</box>
|
||||||
|
: <box></box>}
|
||||||
<box vertical>
|
<box vertical>
|
||||||
<label
|
<Gtk.Label
|
||||||
className="summary"
|
cssName="summary"
|
||||||
halign={START}
|
halign={START}
|
||||||
xalign={0}
|
xalign={0}
|
||||||
label={n.summary}
|
label={n.summary}
|
||||||
truncate
|
// ellipsize={Pango.EllipsizeMode.END}
|
||||||
/>
|
/>
|
||||||
{n.body && <label
|
{n.body ? <label
|
||||||
className="body"
|
cssName="body"
|
||||||
wrap
|
wrap
|
||||||
useMarkup
|
useMarkup
|
||||||
halign={START}
|
halign={START}
|
||||||
xalign={0}
|
xalign={0}
|
||||||
justifyFill
|
|
||||||
label={n.body}
|
label={n.body}
|
||||||
/>}
|
/> : <label></label>}
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
{n.get_actions().length > 0 && <box className="actions">
|
{n.get_actions().length > 0 ? <box cssName="actions">
|
||||||
{n.get_actions().map(({ label, id }) => (
|
{n.get_actions().map(({ label, id }) => (
|
||||||
<button
|
<button
|
||||||
hexpand
|
hexpand
|
||||||
@ -106,7 +98,6 @@ export default function Notification(props: Props) {
|
|||||||
<label label={label} halign={CENTER} hexpand />
|
<label label={label} halign={CENTER} hexpand />
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</box>}
|
</box> : <box></box>}
|
||||||
</box>
|
</box>
|
||||||
</eventbox>
|
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss
|
// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss
|
||||||
$fg-color: #{"@theme_fg_color"};
|
/* $fg-color: #{"@theme_fg_color"}; */
|
||||||
$bg-color: #{"@theme_bg_color"};
|
/* $bg-color: #{"@theme_bg_color"}; */
|
||||||
|
/**/
|
||||||
|
/* window.Bar { */
|
||||||
|
/* background: transparent; */
|
||||||
|
/* color: $fg-color; */
|
||||||
|
/* font-weight: bold; */
|
||||||
|
/**/
|
||||||
|
/* >centerbox { */
|
||||||
|
/* background: $bg-color; */
|
||||||
|
/* border-radius: 10px; */
|
||||||
|
/* margin: 8px; */
|
||||||
|
/* } */
|
||||||
|
/**/
|
||||||
|
/* button { */
|
||||||
|
/* border-radius: 8px; */
|
||||||
|
/* margin: 2px; */
|
||||||
|
/* } */
|
||||||
|
/* } */
|
||||||
|
|
||||||
window.Bar {
|
@use './components/notifications/notifications.scss'
|
||||||
background: transparent;
|
|
||||||
color: $fg-color;
|
|
||||||
font-weight: bold;
|
|
||||||
|
|
||||||
>centerbox {
|
|
||||||
background: $bg-color;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 8px;
|
|
||||||
margin: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -9,6 +9,6 @@
|
|||||||
// "checkJs": true,
|
// "checkJs": true,
|
||||||
// "allowJs": true,
|
// "allowJs": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"jsxImportSource": "astal/gtk3",
|
"jsxImportSource": "astal/gtk4",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
notes.md
12
notes.md
@ -34,6 +34,8 @@
|
|||||||
- [ ] Rofi
|
- [ ] Rofi
|
||||||
- [ ] Spotlight-Search (or replace with anyrun)
|
- [ ] Spotlight-Search (or replace with anyrun)
|
||||||
- [ ] Wallpaper selector (that automatically triggers the theming script)
|
- [ ] Wallpaper selector (that automatically triggers the theming script)
|
||||||
|
- [ ] Kitty
|
||||||
|
- [ ] Configure colours
|
||||||
- [ ] Hyprland
|
- [ ] Hyprland
|
||||||
- [ ] Keybinds: Resize window, move window, open calculator, plus more programs
|
- [ ] Keybinds: Resize window, move window, open calculator, plus more programs
|
||||||
- [ ] Read docs
|
- [ ] Read docs
|
||||||
@ -42,9 +44,12 @@
|
|||||||
- [ ] New image viewer (eog)
|
- [ ] New image viewer (eog)
|
||||||
- [ ] Other pdf reader (maybe -> zathura)
|
- [ ] Other pdf reader (maybe -> zathura)
|
||||||
- [ ] Maybe TUI archive manager (felix-rs)
|
- [ ] Maybe TUI archive manager (felix-rs)
|
||||||
- [ ] Lazygit: Configure
|
- [ ] Lazygit
|
||||||
- [x] Nvim (other repo)
|
- [ ] Configure
|
||||||
|
- [ ] Nvim (other repo)
|
||||||
- [x] Replace notification handler (noice)
|
- [x] Replace notification handler (noice)
|
||||||
|
- [ ] Configure formatters (of Java, Cpp, TS/JS/Vue, Python)
|
||||||
|
- [ ] Maybe: Add extra configs to commentbox
|
||||||
- [ ] Yazi
|
- [ ] Yazi
|
||||||
- [ ] More keybinds
|
- [ ] More keybinds
|
||||||
- [ ] Configure
|
- [ ] Configure
|
||||||
@ -57,7 +62,8 @@
|
|||||||
- [ ] Theming script
|
- [ ] Theming script
|
||||||
- [ ] Installer for configs
|
- [ ] Installer for configs
|
||||||
- [ ] Vivado cleanup (run after vivado and hope vivado is blocking (or simply execute vivado in /tmp))
|
- [ ] Vivado cleanup (run after vivado and hope vivado is blocking (or simply execute vivado in /tmp))
|
||||||
- [ ] migrate to zoxide from autojump
|
- [x] migrate to zoxide from autojump
|
||||||
|
- [ ] properly swap escape and caps (at lowest level possible)
|
||||||
|
|
||||||
|
|
||||||
Using astal (https://aylur.github.io/astal, which is gjs based), write a component that takes as argument a UIComponent array (pre-defined interface) and depending on what subclass of that interface it is renders a different component for each element.
|
Using astal (https://aylur.github.io/astal, which is gjs based), write a component that takes as argument a UIComponent array (pre-defined interface) and depending on what subclass of that interface it is renders a different component for each element.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user