Restructure, prepare launcher
This commit is contained in:
		
							
								
								
									
										2
									
								
								config/ags/bar/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								config/ags/bar/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| node_modules/ | ||||
| @girs/ | ||||
							
								
								
									
										10
									
								
								config/ags/bar/app.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								config/ags/bar/app.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| import { App } from "astal/gtk3" | ||||
| import style from "./style.scss" | ||||
| import Bar from "./widget/Bar" | ||||
|  | ||||
| App.start({ | ||||
|     css: style, | ||||
|     main() { | ||||
|         App.get_monitors().map(Bar) | ||||
|     }, | ||||
| }) | ||||
							
								
								
									
										21
									
								
								config/ags/bar/env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								config/ags/bar/env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| declare const SRC: string | ||||
|  | ||||
| declare module "inline:*" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
|  | ||||
| declare module "*.scss" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
|  | ||||
| declare module "*.blp" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
|  | ||||
| declare module "*.css" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
							
								
								
									
										6
									
								
								config/ags/bar/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								config/ags/bar/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| { | ||||
|     "name": "astal-shell", | ||||
|     "dependencies": { | ||||
|         "astal": "/usr/share/astal/gjs" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										20
									
								
								config/ags/bar/style.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								config/ags/bar/style.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| // https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss | ||||
| $fg-color: #{"@theme_fg_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; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										14
									
								
								config/ags/bar/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								config/ags/bar/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| { | ||||
|     "$schema": "https://json.schemastore.org/tsconfig", | ||||
|     "compilerOptions": { | ||||
|         "experimentalDecorators": true, | ||||
|         "strict": true, | ||||
|         "target": "ES2022", | ||||
|         "module": "ES2022", | ||||
|         "moduleResolution": "Bundler", | ||||
|         // "checkJs": true, | ||||
|         // "allowJs": true, | ||||
|         "jsx": "react-jsx", | ||||
|         "jsxImportSource": "astal/gtk3", | ||||
|     } | ||||
| } | ||||
							
								
								
									
										31
									
								
								config/ags/bar/widget/Bar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								config/ags/bar/widget/Bar.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| import { App, Astal, Gtk, Gdk } from "astal/gtk3" | ||||
| import { Variable } from "astal" | ||||
|  | ||||
| const time = Variable("").poll(1000, "date") | ||||
|  | ||||
| export default function Bar(gdkmonitor: Gdk.Monitor) { | ||||
|     const { TOP, LEFT, RIGHT } = Astal.WindowAnchor | ||||
|  | ||||
|     return <window | ||||
|         className="Bar" | ||||
|         gdkmonitor={gdkmonitor} | ||||
|         exclusivity={Astal.Exclusivity.EXCLUSIVE} | ||||
|         anchor={TOP | LEFT | RIGHT} | ||||
|         application={App}> | ||||
|         <centerbox> | ||||
|             <button | ||||
|                 onClicked="echo hello" | ||||
|                 halign={Gtk.Align.CENTER} | ||||
|             > | ||||
|                 Welcome to AGS! | ||||
|             </button> | ||||
|             <box /> | ||||
|             <button | ||||
|                 onClicked={() => print("hello")} | ||||
|                 halign={Gtk.Align.CENTER} | ||||
|             > | ||||
|                 <label label={time()} /> | ||||
|             </button> | ||||
|         </centerbox> | ||||
|     </window> | ||||
| } | ||||
							
								
								
									
										2
									
								
								config/ags/launcher/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								config/ags/launcher/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| node_modules/ | ||||
| @girs/ | ||||
							
								
								
									
										10
									
								
								config/ags/launcher/app.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								config/ags/launcher/app.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| import { App } from "astal/gtk3" | ||||
| import style from "./style.scss" | ||||
| import Bar from "./widget/Bar" | ||||
|  | ||||
| App.start({ | ||||
|     css: style, | ||||
|     main() { | ||||
|         App.get_monitors().map(Bar) | ||||
|     }, | ||||
| }) | ||||
							
								
								
									
										62
									
								
								config/ags/launcher/definitions/components.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								config/ags/launcher/definitions/components.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| /* | ||||
| *               dotfiles - components.d.ts | ||||
| * | ||||
| *   Created by Janis Hutz 03/22/2025, Licensed under the GPL V3 License | ||||
| *           https://janishutz.com, development@janishutz.com | ||||
| * | ||||
| * | ||||
| */ | ||||
|  | ||||
| import type { UIComponent, ResultElement } from "./rendering"; | ||||
|  | ||||
|  | ||||
| export interface App extends ResultElement { | ||||
|     /** | ||||
|      * The app start command that will be executed | ||||
|      */ | ||||
|     command: string; | ||||
| } | ||||
|  | ||||
| // TODO: Finish | ||||
| export interface DictionaryEntry extends ResultElement { | ||||
|  | ||||
| } | ||||
|  | ||||
| // TODO: Finish | ||||
| export interface CMDOutput extends ResultElement { | ||||
|  | ||||
| } | ||||
|  | ||||
| // TODO: Finish | ||||
| export interface Calculation extends ResultElement { | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /* ************* * | ||||
|  * UI Components * | ||||
|  * ************* */ | ||||
|   | ||||
| export interface LargeUIComponent extends UIComponent { | ||||
|     /** | ||||
|      * The number of items to display per line. Image size will automatically be scaled | ||||
|      * based on width | ||||
|      */ | ||||
|     itemsPerLine: number; | ||||
| } | ||||
|  | ||||
| export interface MediumUIComponent extends UIComponent {} | ||||
|  | ||||
| export interface ListUIComponent extends UIComponent {} | ||||
|  | ||||
| export interface DictionaryUIComponent extends UIComponent { | ||||
|     elements: DictionaryEntry[]; | ||||
| } | ||||
|  | ||||
| export interface CMDOutputUIComponent extends UIComponent { | ||||
|     elements: CMDOutput[]; | ||||
| } | ||||
|  | ||||
| export interface CalculationUIComponent extends UIComponent { | ||||
|     elements: Calculation[]; | ||||
| } | ||||
							
								
								
									
										0
									
								
								config/ags/launcher/definitions/job.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								config/ags/launcher/definitions/job.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
									
										60
									
								
								config/ags/launcher/definitions/rendering.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								config/ags/launcher/definitions/rendering.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| /* | ||||
| *               dotfiles - rendering.d.ts | ||||
| * | ||||
| *   Created by Janis Hutz 03/22/2025, Licensed under the GPL V3 License | ||||
| *           https://janishutz.com, development@janishutz.com | ||||
| * | ||||
| * | ||||
| */ | ||||
|  | ||||
| export interface UIComponent { | ||||
|     /** | ||||
|      * The title of the component (like a category name), shown above small divider line | ||||
|      */ | ||||
|     title: string; | ||||
|  | ||||
|     /** | ||||
|      * ResultElement list, made up of all elements that should be shown | ||||
|      */ | ||||
|     elements: ResultElement[]; | ||||
|  | ||||
|     /** | ||||
|      * Choose how many elements to show before truncating (will expand when command is run) | ||||
|      */ | ||||
|     truncate: number; | ||||
|  | ||||
|     /** | ||||
|      * The weight of the element (determines order) | ||||
|      */ | ||||
|     weight: number; | ||||
| } | ||||
|  | ||||
|  | ||||
| export interface ResultElement { | ||||
|     /** | ||||
|      * The name of the result element | ||||
|      */ | ||||
|     name: string; | ||||
|  | ||||
|     /** | ||||
|      * Path to the image to be displayed in the UI | ||||
|      */ | ||||
|     img: string; | ||||
|  | ||||
|     /** | ||||
|      * The weight of the element (determines order) | ||||
|      */ | ||||
|     weight: number; | ||||
|  | ||||
|     /** | ||||
|      * The action to be executed | ||||
|      */ | ||||
|     action: Action; | ||||
|  | ||||
|     /** | ||||
|      * The font size of the text (optional) | ||||
|      */ | ||||
|     fontSize: number | undefined; | ||||
| } | ||||
|  | ||||
| type Action = ''; | ||||
							
								
								
									
										21
									
								
								config/ags/launcher/env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								config/ags/launcher/env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| declare const SRC: string | ||||
|  | ||||
| declare module "inline:*" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
|  | ||||
| declare module "*.scss" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
|  | ||||
| declare module "*.blp" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
|  | ||||
| declare module "*.css" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
							
								
								
									
										6
									
								
								config/ags/launcher/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								config/ags/launcher/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| { | ||||
|     "name": "astal-shell", | ||||
|     "dependencies": { | ||||
|         "astal": "/usr/share/astal/gjs" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										20
									
								
								config/ags/launcher/style.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								config/ags/launcher/style.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| // https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss | ||||
| $fg-color: #{"@theme_fg_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; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										14
									
								
								config/ags/launcher/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								config/ags/launcher/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| { | ||||
|     "$schema": "https://json.schemastore.org/tsconfig", | ||||
|     "compilerOptions": { | ||||
|         "experimentalDecorators": true, | ||||
|         "strict": true, | ||||
|         "target": "ES2022", | ||||
|         "module": "ES2022", | ||||
|         "moduleResolution": "Bundler", | ||||
|         // "checkJs": true, | ||||
|         // "allowJs": true, | ||||
|         "jsx": "react-jsx", | ||||
|         "jsxImportSource": "astal/gtk3", | ||||
|     } | ||||
| } | ||||
							
								
								
									
										0
									
								
								config/ags/launcher/ui/AppLauncher.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								config/ags/launcher/ui/AppLauncher.tsx
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								config/ags/launcher/ui/components/calc.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								config/ags/launcher/ui/components/calc.tsx
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								config/ags/launcher/ui/components/cmd.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								config/ags/launcher/ui/components/cmd.tsx
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								config/ags/launcher/ui/components/dict.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								config/ags/launcher/ui/components/dict.tsx
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								config/ags/launcher/ui/components/large.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								config/ags/launcher/ui/components/large.tsx
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								config/ags/launcher/ui/components/list.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								config/ags/launcher/ui/components/list.tsx
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								config/ags/launcher/ui/components/medium.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								config/ags/launcher/ui/components/medium.tsx
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										10
									
								
								config/ags/launcher/util/file.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								config/ags/launcher/util/file.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| /* | ||||
| *               dotfiles - file.ts | ||||
| * | ||||
| *   Created by Janis Hutz 03/22/2025, Licensed under the GPL V3 License | ||||
| *           https://janishutz.com, development@janishutz.com | ||||
| * | ||||
| * | ||||
| */ | ||||
|  | ||||
| import { readFileAsync, writeFileAsync, monitorFile } from "astal"; | ||||
							
								
								
									
										0
									
								
								config/ags/launcher/util/fzf.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								config/ags/launcher/util/fzf.ts
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								config/ags/launcher/util/search.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								config/ags/launcher/util/search.ts
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										43
									
								
								config/ags/launcher/util/subprocessRunner.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								config/ags/launcher/util/subprocessRunner.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| /* | ||||
|  *               dotfiles - subprocessRunner.ts | ||||
|  * | ||||
|  *   Created by Janis Hutz 03/22/2025, Licensed under the GPL V3 License | ||||
|  *           https://janishutz.com, development@janishutz.com | ||||
|  * | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| import { subprocess, execAsync, Process } from "astal/process"; | ||||
|  | ||||
| // TODO: Get cwd and the likes to then use that to run JavaScript files with node / python with python, etc | ||||
|  | ||||
| /** | ||||
|  * Run a subprocess. If you simply want to run a command that doesn't need continuous updates | ||||
|  * run executeCommand instead. | ||||
|  * @param cmd - The command to be run | ||||
|  * @param onOut - Calback function for stdout of the subprocess | ||||
|  * @param onErr - [TODO:description] | ||||
|  * @returns [TODO:return] | ||||
|  */ | ||||
| const startSubProcess = ( | ||||
|   cmd: string | string[], | ||||
|   onOut: (stdout: string) => void, | ||||
|   onErr: (stderr: string) => void | undefined, | ||||
| ): Process => { | ||||
|     return subprocess( cmd, onOut, onErr ); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Run a command. If you need continuous updates, run startSubProcess instead  | ||||
|  * @param cmd - The command to be run. Either a string or an array of strings | ||||
|  * @returns A Promise resolving to stdout of the command | ||||
|  */ | ||||
| const executeCommand = (cmd: string | string[]): Promise<string> => { | ||||
|     return execAsync( cmd ); | ||||
| }; | ||||
|  | ||||
|  | ||||
| export default { | ||||
|     startSubProcess, | ||||
|     executeCommand | ||||
| } | ||||
							
								
								
									
										2
									
								
								config/ags/notifications/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								config/ags/notifications/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| node_modules/ | ||||
| @girs/ | ||||
							
								
								
									
										29
									
								
								config/ags/notifications/app.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								config/ags/notifications/app.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| import { App } from "astal/gtk3" | ||||
| import style from "./style.scss" | ||||
|  | ||||
| import not from "./handler" | ||||
|  | ||||
| App.start({ | ||||
|     instanceName: "notifier", | ||||
|     css: style, | ||||
|     main() { | ||||
|         not.startNotificationHandler( 0, App.get_monitors()[0] ) | ||||
|     }, | ||||
|     requestHandler(request, res) { | ||||
|         if ( request == 'show' ) { | ||||
|             not.openNotificationMenu( 0 ); | ||||
|             res( 'Showing all open notifications' ); | ||||
|         } else if ( request == 'hide' ) { | ||||
|             not.closeNotificationMenu( 0 ); | ||||
|             res( 'Hid all notifications' ); | ||||
|         } else if ( request == 'clear' ) { | ||||
|             not.clearAllNotifications( 0 ); | ||||
|             res( 'Cleared all notifications' ); | ||||
|         } else if ( request == 'clear-newest' ) { | ||||
|             not.clearNewestNotifications( 0 ); | ||||
|             res( 'Cleared newest notification' ); | ||||
|         } else { | ||||
|             res( 'Unknown command!' ); | ||||
|         } | ||||
|     }, | ||||
| }) | ||||
							
								
								
									
										21
									
								
								config/ags/notifications/env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								config/ags/notifications/env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| declare const SRC: string | ||||
|  | ||||
| declare module "inline:*" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
|  | ||||
| declare module "*.scss" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
|  | ||||
| declare module "*.blp" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
|  | ||||
| declare module "*.css" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
							
								
								
									
										184
									
								
								config/ags/notifications/handler.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								config/ags/notifications/handler.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | ||||
| /* | ||||
| *               dotfiles - handler.ts | ||||
| * | ||||
| *   Created by Janis Hutz 03/21/2025, Licensed under the GPL V3 License | ||||
| *           https://janishutz.com, development@janishutz.com | ||||
| * | ||||
| * | ||||
| */ | ||||
|  | ||||
| import { Astal, Gtk, Gdk } from "astal/gtk3" | ||||
| import Notifd from "gi://AstalNotifd"; | ||||
| import Notification from "./notifications/notifications"; | ||||
| import { type Subscribable } from "astal/binding"; | ||||
| import { Variable, bind, timeout } from "astal" | ||||
|  | ||||
| // Config | ||||
| const TIMEOUT_DELAY = 5000; | ||||
|  | ||||
| class Notifier implements Subscribable { | ||||
|     private display: Map<number, Gtk.Widget> = new Map(); | ||||
|     private notifications: Map<number, Notifd.Notification> = new Map(); | ||||
|  | ||||
|     private notifd: Notifd.Notifd; | ||||
|     private subscriberData: Variable<Gtk.Widget[]> = Variable( [] ); | ||||
|     private instanceID: number; | ||||
|     private menuOpen: boolean; | ||||
|  | ||||
|     /** | ||||
|      * Sets up the notifier | ||||
|      */ | ||||
|     constructor( id: number ) { | ||||
|         this.instanceID = id; | ||||
|         this.menuOpen = false; | ||||
|         this.notifd = Notifd.get_default(); | ||||
|         this.notifd.ignoreTimeout = true; | ||||
|  | ||||
|         this.notifd.connect( 'notified', ( _, id ) => { | ||||
|             this.add( id ); | ||||
|         } ); | ||||
|  | ||||
|         this.notifd.connect( 'resolved', ( _, id ) => { | ||||
|             this.hide( 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 | ||||
|      * @param id - The id of the element to be shown | ||||
|      */ | ||||
|     private show ( id: number ) { | ||||
|         this.set( id, Notification( { | ||||
|             notification: this.notifications.get( id )!, | ||||
|             onHoverLost: () => 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 | ||||
|      */ | ||||
|     private set ( id: number, widget: Gtk.Widget ) { | ||||
|         this.display.get( id )?.destroy(); | ||||
|         this.display.set( id, widget ); | ||||
|         this.notify(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Hide, not delete notification (= send to notification centre) | ||||
|      * @param id - The id of the notification to hide | ||||
|      */ | ||||
|     private hide ( id: number ) { | ||||
|         this.display.get( id )?.destroy(); | ||||
|         this.display.delete( id ); | ||||
|         this.notify(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Delete a notification (from notification centre too) | ||||
|      * @param id - The id of the notification to hide | ||||
|      */ | ||||
|     delete ( id: number ) { | ||||
|         this.hide( id ); | ||||
|         this.notifications.get( id )?.dismiss(); | ||||
|         this.notifications.delete( id ); | ||||
|     } | ||||
|  | ||||
|     openNotificationMenu () { | ||||
|         // Show all notifications that have not been cleared | ||||
|         this.menuOpen = true; | ||||
|         this.notifications.forEach( ( _, id ) => { | ||||
|             this.show( id ); | ||||
|         } ) | ||||
|     } | ||||
|  | ||||
|     hideNotifications () { | ||||
|         this.menuOpen = false; | ||||
|         this.notifications.forEach( ( _, id ) => { | ||||
|             this.hide( id ); | ||||
|         } ) | ||||
|     } | ||||
|  | ||||
|     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 ); | ||||
| } | ||||
|  | ||||
| const openNotificationMenu = ( id: number ) => { | ||||
|     notifiers.get( id )?.openNotificationMenu(); | ||||
| } | ||||
|  | ||||
| const closeNotificationMenu = ( id: number ) => { | ||||
|     notifiers.get( id )?.hideNotifications(); | ||||
| } | ||||
|  | ||||
| const clearAllNotifications = ( id: number ) => { | ||||
|     notifiers.get( id )?.clearAllNotifications(); | ||||
| } | ||||
|  | ||||
| const clearNewestNotifications = ( id: number ) => { | ||||
|     notifiers.get( id )?.clearNewestNotification(); | ||||
| } | ||||
|  | ||||
| const startNotificationHandler = (id: number, gdkmonitor: Gdk.Monitor) => { | ||||
|     const { TOP, RIGHT } = Astal.WindowAnchor | ||||
|     const notifier: Notifier = new Notifier( id ); | ||||
|     notifiers.set( id, notifier ); | ||||
|  | ||||
|     return <window | ||||
|         className="NotificationHandler" | ||||
|         gdkmonitor={gdkmonitor} | ||||
|         exclusivity={Astal.Exclusivity.EXCLUSIVE} | ||||
|         anchor={TOP | RIGHT}> | ||||
|         <box vertical noImplicitDestroy> | ||||
|             {bind(notifier)} | ||||
|         </box> | ||||
|     </window> | ||||
| } | ||||
|  | ||||
|  | ||||
| export default { | ||||
|     startNotificationHandler, | ||||
|     openNotificationMenu, | ||||
|     closeNotificationMenu, | ||||
|     clearAllNotifications, | ||||
|     clearNewestNotifications | ||||
| } | ||||
							
								
								
									
										125
									
								
								config/ags/notifications/notifications/notifications.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								config/ags/notifications/notifications/notifications.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | ||||
| @use "sass:string"; | ||||
|  | ||||
| @function gtkalpha($c, $a) { | ||||
|     @return string.unquote("alpha(#{$c},#{$a})"); | ||||
| } | ||||
|  | ||||
| // https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss | ||||
| $fg-color: #{"@theme_fg_color"}; | ||||
| $bg-color: #{"@theme_bg_color"}; | ||||
| $error: red; | ||||
|  | ||||
| window.NotificationPopups { | ||||
|     all: unset; | ||||
| } | ||||
|  | ||||
| eventbox.Notification { | ||||
|  | ||||
|     &:first-child>box { | ||||
|         margin-top: 1rem; | ||||
|     } | ||||
|  | ||||
|     &:last-child>box { | ||||
|         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 { | ||||
|         border: 1pt solid gtkalpha($error, .4); | ||||
|  | ||||
|         .header { | ||||
|  | ||||
|             .app-name { | ||||
|                 color: gtkalpha($error, .8); | ||||
|  | ||||
|             } | ||||
|  | ||||
|             .app-icon { | ||||
|                 color: gtkalpha($error, .6); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .header { | ||||
|         padding: .5rem; | ||||
|         color: gtkalpha($fg-color, 0.5); | ||||
|  | ||||
|         .app-icon { | ||||
|             margin: 0 .4rem; | ||||
|         } | ||||
|  | ||||
|         .app-name { | ||||
|             margin-right: .3rem; | ||||
|             font-weight: bold; | ||||
|  | ||||
|             &:first-child { | ||||
|                 margin-left: .4rem; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         .time { | ||||
|             margin: 0 .4rem; | ||||
|         } | ||||
|  | ||||
|         button { | ||||
|             padding: .2rem; | ||||
|             min-width: 0; | ||||
|             min-height: 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     separator { | ||||
|         margin: 0 .4rem; | ||||
|         background-color: gtkalpha($fg-color, .1); | ||||
|     } | ||||
|  | ||||
|     .content { | ||||
|         margin: 1rem; | ||||
|         margin-top: .5rem; | ||||
|  | ||||
|         .summary { | ||||
|             font-size: 1.2em; | ||||
|             color: $fg-color; | ||||
|         } | ||||
|  | ||||
|         .body { | ||||
|             color: gtkalpha($fg-color, 0.8); | ||||
|         } | ||||
|  | ||||
|         .image { | ||||
|             border: 1px solid gtkalpha($fg-color, .02); | ||||
|             margin-right: .5rem; | ||||
|             border-radius: 9px; | ||||
|             min-width: 100px; | ||||
|             min-height: 100px; | ||||
|             background-size: cover; | ||||
|             background-position: center; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .actions { | ||||
|         margin: 1rem; | ||||
|         margin-top: 0; | ||||
|  | ||||
|         button { | ||||
|             margin: 0 .3rem; | ||||
|  | ||||
|             &:first-child { | ||||
|                 margin-left: 0; | ||||
|             } | ||||
|  | ||||
|             &:last-child { | ||||
|                 margin-right: 0; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										112
									
								
								config/ags/notifications/notifications/notifications.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								config/ags/notifications/notifications/notifications.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| // From astal examples  | ||||
|  | ||||
| import { GLib } from "astal" | ||||
| import { Gtk, Astal } from "astal/gtk3" | ||||
| import { type EventBox } from "astal/gtk3/widget" | ||||
| import Notifd from "gi://AstalNotifd" | ||||
|  | ||||
| const isIcon = (icon: string) => | ||||
|     !!Astal.Icon.lookup_icon(icon) | ||||
|  | ||||
| const fileExists = (path: string) => | ||||
|     GLib.file_test(path, GLib.FileTest.EXISTS) | ||||
|  | ||||
| const time = (time: number, format = "%H:%M") => GLib.DateTime | ||||
|     .new_from_unix_local(time) | ||||
|     .format(format)! | ||||
|  | ||||
| const urgency = (n: Notifd.Notification) => { | ||||
|     const { LOW, NORMAL, CRITICAL } = Notifd.Urgency | ||||
|     // match operator when? | ||||
|     switch (n.urgency) { | ||||
|         case LOW: return "low" | ||||
|         case CRITICAL: return "critical" | ||||
|         case NORMAL: | ||||
|         default: return "normal" | ||||
|     } | ||||
| } | ||||
|  | ||||
| type Props = { | ||||
|     delete( id: number, instanceID: number ): void | ||||
|     setup(self: EventBox): void | ||||
|     onHoverLost(self: EventBox): void | ||||
|     notification: Notifd.Notification | ||||
|     id: number | ||||
|     instanceID: number | ||||
| } | ||||
|  | ||||
| export default function Notification(props: Props) { | ||||
|     const { notification: n, onHoverLost, setup, id: id, delete: del, instanceID: instance } = props | ||||
|     const { START, CENTER, END } = Gtk.Align | ||||
|  | ||||
|     return <eventbox | ||||
|         className={`Notification ${urgency(n)}`} | ||||
|         setup={setup} | ||||
|         onHoverLost={onHoverLost}> | ||||
|         <box vertical> | ||||
|             <box className="header"> | ||||
|                 {(n.appIcon || n.desktopEntry) && <icon | ||||
|                     className="app-icon" | ||||
|                     visible={Boolean(n.appIcon || n.desktopEntry)} | ||||
|                     icon={n.appIcon || n.desktopEntry} | ||||
|                 />} | ||||
|                 <label | ||||
|                     className="app-name" | ||||
|                     halign={START} | ||||
|                     truncate | ||||
|                     label={n.appName || "Unknown"} | ||||
|                 /> | ||||
|                 <label | ||||
|                     className="time" | ||||
|                     hexpand | ||||
|                     halign={END} | ||||
|                     label={time(n.time)} | ||||
|                 /> | ||||
|                 <button onClicked={() => del( id, instance )}> | ||||
|                     <icon icon="window-close-symbolic" /> | ||||
|                 </button> | ||||
|             </box> | ||||
|             <Gtk.Separator visible /> | ||||
|             <box className="content"> | ||||
|                 {n.image && fileExists(n.image) && <box | ||||
|                     valign={START} | ||||
|                     className="image" | ||||
|                     css={`background-image: url('${n.image}')`} | ||||
|                 />} | ||||
|                 {n.image && isIcon(n.image) && <box | ||||
|                     expand={false} | ||||
|                     valign={START} | ||||
|                     className="icon-image"> | ||||
|                     <icon icon={n.image} expand halign={CENTER} valign={CENTER} /> | ||||
|                 </box>} | ||||
|                 <box vertical> | ||||
|                     <label | ||||
|                         className="summary" | ||||
|                         halign={START} | ||||
|                         xalign={0} | ||||
|                         label={n.summary} | ||||
|                         truncate | ||||
|                     /> | ||||
|                     {n.body && <label | ||||
|                         className="body" | ||||
|                         wrap | ||||
|                         useMarkup | ||||
|                         halign={START} | ||||
|                         xalign={0} | ||||
|                         justifyFill | ||||
|                         label={n.body} | ||||
|                     />} | ||||
|                 </box> | ||||
|             </box> | ||||
|             {n.get_actions().length > 0 && <box className="actions"> | ||||
|                 {n.get_actions().map(({ label, id }) => ( | ||||
|                     <button | ||||
|                         hexpand | ||||
|                         onClicked={() => n.invoke(id)}> | ||||
|                         <label label={label} halign={CENTER} hexpand /> | ||||
|                     </button> | ||||
|                 ))} | ||||
|             </box>} | ||||
|         </box> | ||||
|     </eventbox> | ||||
| } | ||||
							
								
								
									
										6
									
								
								config/ags/notifications/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								config/ags/notifications/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| { | ||||
|     "name": "astal-shell", | ||||
|     "dependencies": { | ||||
|         "astal": "/usr/share/astal/gjs" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										2
									
								
								config/ags/notifications/style.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								config/ags/notifications/style.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| // Import notification box style | ||||
| @use "./notifications/notifications.scss" | ||||
							
								
								
									
										14
									
								
								config/ags/notifications/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								config/ags/notifications/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| { | ||||
|     "$schema": "https://json.schemastore.org/tsconfig", | ||||
|     "compilerOptions": { | ||||
|         "experimentalDecorators": true, | ||||
|         "strict": true, | ||||
|         "target": "ES2022", | ||||
|         "module": "ES2022", | ||||
|         "moduleResolution": "Bundler", | ||||
|         // "checkJs": true, | ||||
|         // "allowJs": true, | ||||
|         "jsx": "react-jsx", | ||||
|         "jsxImportSource": "astal/gtk3", | ||||
|     } | ||||
| } | ||||
							
								
								
									
										2
									
								
								config/ags/quickactions/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								config/ags/quickactions/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| node_modules/ | ||||
| @girs/ | ||||
							
								
								
									
										10
									
								
								config/ags/quickactions/app.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								config/ags/quickactions/app.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| import { App } from "astal/gtk3" | ||||
| import style from "./style.scss" | ||||
| import Bar from "./widget/Bar" | ||||
|  | ||||
| App.start({ | ||||
|     css: style, | ||||
|     main() { | ||||
|         App.get_monitors().map(Bar) | ||||
|     }, | ||||
| }) | ||||
							
								
								
									
										21
									
								
								config/ags/quickactions/env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								config/ags/quickactions/env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| declare const SRC: string | ||||
|  | ||||
| declare module "inline:*" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
|  | ||||
| declare module "*.scss" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
|  | ||||
| declare module "*.blp" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
|  | ||||
| declare module "*.css" { | ||||
|     const content: string | ||||
|     export default content | ||||
| } | ||||
							
								
								
									
										6
									
								
								config/ags/quickactions/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								config/ags/quickactions/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| { | ||||
|     "name": "astal-shell", | ||||
|     "dependencies": { | ||||
|         "astal": "/usr/share/astal/gjs" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										20
									
								
								config/ags/quickactions/style.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								config/ags/quickactions/style.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| // https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss | ||||
| $fg-color: #{"@theme_fg_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; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										14
									
								
								config/ags/quickactions/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								config/ags/quickactions/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| { | ||||
|     "$schema": "https://json.schemastore.org/tsconfig", | ||||
|     "compilerOptions": { | ||||
|         "experimentalDecorators": true, | ||||
|         "strict": true, | ||||
|         "target": "ES2022", | ||||
|         "module": "ES2022", | ||||
|         "moduleResolution": "Bundler", | ||||
|         // "checkJs": true, | ||||
|         // "allowJs": true, | ||||
|         "jsx": "react-jsx", | ||||
|         "jsxImportSource": "astal/gtk3", | ||||
|     } | ||||
| } | ||||
							
								
								
									
										31
									
								
								config/ags/quickactions/widget/Bar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								config/ags/quickactions/widget/Bar.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| import { App, Astal, Gtk, Gdk } from "astal/gtk3" | ||||
| import { Variable } from "astal" | ||||
|  | ||||
| const time = Variable("").poll(1000, "date") | ||||
|  | ||||
| export default function Bar(gdkmonitor: Gdk.Monitor) { | ||||
|     const { TOP, LEFT, RIGHT } = Astal.WindowAnchor | ||||
|  | ||||
|     return <window | ||||
|         className="Bar" | ||||
|         gdkmonitor={gdkmonitor} | ||||
|         exclusivity={Astal.Exclusivity.EXCLUSIVE} | ||||
|         anchor={TOP | LEFT | RIGHT} | ||||
|         application={App}> | ||||
|         <centerbox> | ||||
|             <button | ||||
|                 onClicked="echo hello" | ||||
|                 halign={Gtk.Align.CENTER} | ||||
|             > | ||||
|                 Welcome to AGS! | ||||
|             </button> | ||||
|             <box /> | ||||
|             <button | ||||
|                 onClicked={() => print("hello")} | ||||
|                 halign={Gtk.Align.CENTER} | ||||
|             > | ||||
|                 <label label={time()} /> | ||||
|             </button> | ||||
|         </centerbox> | ||||
|     </window> | ||||
| } | ||||
		Reference in New Issue
	
	Block a user