diff --git a/modules/ags/astal/greeter.ts b/modules/ags/astal/greeter.ts new file mode 100644 index 0000000..be1e95b --- /dev/null +++ b/modules/ags/astal/greeter.ts @@ -0,0 +1,7 @@ +import Greeter from './ts/greetd/main'; + +App.config({ + windows: () => [ + Greeter(), + ], +}); diff --git a/modules/ags/astal/js/utils.js b/modules/ags/astal/js/utils.js index f7cce39..3bb911b 100644 --- a/modules/ags/astal/js/utils.js +++ b/modules/ags/astal/js/utils.js @@ -29,19 +29,19 @@ export const transpileTypeScript = async(host) => { // Create the dir if it doesn't exist `mkdir -p /tmp/astal-${host}; ` + + // Let bun see tsconfig.json + `cd ${App.configDir};` + + `bun build ${App.configDir}/${host}.ts ` + '--external resource:///* ' + '--external gi://* ' + '--external cairo ' + - '--external */fzf.es.js ' + - // Since bun wants to right in cwd, we just redirect stdin instead + // Since bun wants to write in cwd, we just redirect stdin instead `> ${outPath}`, ]).catch(print); - if (host !== 'greeter') { - watchAndCompileSass(host); - } + watchAndCompileSass(host); return await import(`file://${outPath}`); }; diff --git a/modules/ags/astal/scss/greeter.scss b/modules/ags/astal/scss/greeter.scss new file mode 100644 index 0000000..34cf779 --- /dev/null +++ b/modules/ags/astal/scss/greeter.scss @@ -0,0 +1,16 @@ +window { + all: unset; + background-color: transparent; +} + + +.base { + background-color: #{"@window_bg_color"}; + border: 1.3px solid #{"@accent_bg_color"}; + border-radius: 12px; + padding: 5px; +} + +dropdown popover.menu { + padding-top: 0; +} diff --git a/modules/ags/astal/scss/wim.scss b/modules/ags/astal/scss/wim.scss deleted file mode 100644 index 1a14d46..0000000 --- a/modules/ags/astal/scss/wim.scss +++ /dev/null @@ -1,10 +0,0 @@ -window { - all: unset; -} - - -.base { - background-color: #{"@window_bg_color"}; - border: 1px solid #{"@accent_bg_color"}; - padding: 5px; -} diff --git a/modules/ags/astal/ts/greetd/main.ts b/modules/ags/astal/ts/greetd/main.ts new file mode 100644 index 0000000..ca1cefa --- /dev/null +++ b/modules/ags/astal/ts/greetd/main.ts @@ -0,0 +1,115 @@ +const { Box, Entry, Label, Window } = Widget; +const { execAsync, idle, readFileAsync } = Utils; + +const greetd = await Service.import('greetd'); + +const { Gtk } = imports.gi; + +const DEFAULT_NAME = 'matt'; + +// Types +import { StringObject } from 'types/@girs/gtk-4.0/gtk-4.0.cjs'; + + +// Run Wallpaper daemon here to not cause issues at startup +execAsync(['bash', '-c', + `swww init --no-cache && swww img -t none ${App.configDir}/.wallpaper`]).catch(print); + +const parsePasswd = (fileContent: string) => { + const splitUsers = fileContent.split('\n'); + const parsedUsers = splitUsers.map((u) => { + const user = u.split(':'); + + return { + name: user[0], + uid: Number(user[2]), + gid: Number(user[3]), + desc: user[4], + home: user[5], + shell: user[6], + }; + }); + + // Filter out system users, nixbld users and nobody + return parsedUsers.filter((u) => { + return u.uid >= 1000 && + !u.name.includes('nixbld') && + u.name !== 'nobody'; + }); +}; +const users = parsePasswd(await readFileAsync('/etc/passwd')); + +const dropdown = Gtk.DropDown.new_from_strings(users.map((u) => u.name)); + +const password = Entry({ + placeholderText: 'Password', + visibility: false, + + setup: (self) => idle(() => { + self.grab_focus(); + }), + + on_accept: () => { + greetd.login( + (dropdown.selectedItem as StringObject)['string'] || '', + password.text || '', + 'Hyprland', + + ).catch((error) => { + response.label = JSON.stringify(error); + }); + }, + +}); + +const response = Label(); + +export default () => Window({ + name: 'greeter', + keymode: 'on-demand', + + child: Box({ + vertical: true, + hpack: 'center', + vpack: 'center', + hexpand: true, + vexpand: true, + cssClasses: ['base'], + + children: [ + Box({ + vertical: true, + hpack: 'center', + vpack: 'center', + hexpand: true, + vexpand: true, + + setup: (self) => { + self.add_css_class('linked'); + + idle(() => { + const usernames = [] as string[]; + + for (let i = 0; i < dropdown.model.get_n_items(); ++i) { + const name = (dropdown.model.get_item(i) as StringObject)['string']; + + if (name) { + usernames.push(name); + } + } + + if (usernames.includes(DEFAULT_NAME)) { + dropdown.set_selected(usernames.indexOf(DEFAULT_NAME)); + } + }); + }, + + children: [ + dropdown, + password, + ], + }), + response, + ], + }), +}); diff --git a/modules/ags/astal/wim.ts b/modules/ags/astal/wim.ts deleted file mode 100644 index e6c546a..0000000 --- a/modules/ags/astal/wim.ts +++ /dev/null @@ -1,20 +0,0 @@ -import Adw from 'gi://Adw'; - - -App.config({ - windows: () => [ - Widget.Window({ - name: 'test', - - child: Widget.Box({ - setup: (self) => { - self.toggleCssClass('base'); - }, - - child: new Adw.SplitButton({ - label: 'test', - }), - }), - }), - ], -}); diff --git a/modules/ags/config/greeter.ts b/modules/ags/config/greeter.ts deleted file mode 100644 index 11cf01c..0000000 --- a/modules/ags/config/greeter.ts +++ /dev/null @@ -1,140 +0,0 @@ -/* eslint no-magic-numbers: 0 */ - -const { Box, Button, Entry, Label, Menu, MenuItem, Window } = Widget; -const { execAsync, idle, readFileAsync } = Utils; - -const greetd = await Service.import('greetd'); - -const { Gdk } = imports.gi; - -const DEFAULT_NAME = 'matt'; - -// Types -type User = { - name: string; - uid: number; - gid: number; - desc: string; - home: string; - shell: string; -}; - - -// Run Wallpaper daemon here to not cause issues at startup -execAsync(['swww', 'init', '--no-cache']).then(() => { - execAsync([ - 'swww', 'img', '-t', 'none', - `${App.configDir}/.wallpaper`, - ]).catch(print); -}).catch(print); - -// Put ref of Label here to change it easily later -const name = Label(DEFAULT_NAME); - -// Initiate menu here to not have garbage collection take it away -// TODO: figure out type -let menu; - -const parsePasswd = (fileContent: string) => { - const splitUsers = fileContent.split('\n'); - const parsedUsers = splitUsers.map((u) => { - const user = u.split(':'); - - return { - name: user[0], - uid: Number(user[2]), - gid: Number(user[3]), - desc: user[4], - home: user[5], - shell: user[6], - }; - }); - - // Filter out system users, nixbld users and nobody - return parsedUsers.filter((u) => { - return u.uid >= 1000 && - !u.name.includes('nixbld') && - u.name !== 'nobody'; - }); -}; - -// FIXME: make menu scrollable -const DropdownMenu = (users: User[]) => Menu({ - attach_widget: dropdown, - children: users.map((u) => MenuItem({ - on_activate: () => { - name.label = u.name; - }, - - child: Label({ - label: u.name, - justification: 'center', - css: `min-width: ${dropdown.get_allocated_width() / 2}px;`, - }), - })), -}); - -const dropdown = Button({ - child: name, - - setup: () => { - idle(() => { - readFileAsync('/etc/passwd').then((out) => { - const users = parsePasswd(out); - - menu = DropdownMenu(users); - }).catch(print); - }); - }, - - on_primary_click_release: (self, event) => { - menu.popup_at_widget( - self, - Gdk.Gravity.SOUTH, - Gdk.Gravity.NORTH, - event, - ); - }, -}); - -const password = Entry({ - placeholder_text: 'Password', - visibility: false, - - on_accept: () => { - greetd.login( - name.label || '', - password.text || '', - 'Hyprland', - - ).catch((error) => { - response.label = JSON.stringify(error); - }); - }, - -}).on('realize', (entry) => entry.grab_focus()); - -const response = Label(); - -const win = Window({ - name: 'greeter', - css: 'background-color: transparent;', - anchor: ['top', 'left', 'right', 'bottom'], - keymode: 'on-demand', - - child: Box({ - vertical: true, - hpack: 'center', - vpack: 'center', - hexpand: true, - vexpand: true, - - children: [ - dropdown, - password, - response, - ], - }), -}); - -export default { windows: [win] }; diff --git a/modules/ags/config/js/utils.js b/modules/ags/config/js/utils.js index ed29593..7ed4398 100644 --- a/modules/ags/config/js/utils.js +++ b/modules/ags/config/js/utils.js @@ -41,9 +41,7 @@ export const transpileTypeScript = async(host) => { `> ${outPath}`, ]).catch(print); - if (host !== 'greeter') { - watchAndCompileSass(host); - } + watchAndCompileSass(host); return await import(`file://${outPath}`); }; diff --git a/modules/ags/config/test-greeter.js b/modules/ags/config/test-greeter.js deleted file mode 100644 index 057bfb1..0000000 --- a/modules/ags/config/test-greeter.js +++ /dev/null @@ -1,4 +0,0 @@ -// Delete /tmp/ags-greeter before and after using this -import { transpileTypeScript } from './js/utils.js'; - -export default (await transpileTypeScript('greeter')).default; diff --git a/modules/greetd/ags.nix b/modules/greetd/astal.nix similarity index 76% rename from modules/greetd/ags.nix rename to modules/greetd/astal.nix index a23ae86..6c1db7b 100644 --- a/modules/greetd/ags.nix +++ b/modules/greetd/astal.nix @@ -1,5 +1,5 @@ { - ags, + astal, config, pkgs, ... @@ -15,12 +15,12 @@ in { home-manager.users.greeter = { imports = [ - ags.homeManagerModules.default + astal.homeManagerModules.default ../../common/vars ../../home/theme ]; - programs.ags.enable = true; + programs.astal.enable = true; home = { packages = [ @@ -33,14 +33,14 @@ in { ]; file = { - ".config/ags/.wallpaper".source = "${pkgs.dracula-theme}/wallpapers/waves.png"; + ".config/astal/.wallpaper".source = "${pkgs.dracula-theme}/wallpapers/waves.png"; - ".config/ags" = { - source = ../ags/config; + ".config/astal" = { + source = ../ags/astal; recursive = true; }; - ".config/ags/config.js".text = + ".config/astal/config.js".text = /* javascript */ diff --git a/modules/greetd/default.nix b/modules/greetd/default.nix index 007ca76..4dcefc0 100644 --- a/modules/greetd/default.nix +++ b/modules/greetd/default.nix @@ -11,7 +11,7 @@ isTouchscreen = config.hardware.sensor.iio.enable; hyprland = config.home-manager.users.${mainUser}.wayland.windowManager.hyprland.finalPackage; in { - imports = [./ags.nix]; + imports = [./astal.nix]; services = { xserver = { diff --git a/modules/greetd/hyprland.nix b/modules/greetd/hyprland.nix index 7ee4066..a4f0909 100644 --- a/modules/greetd/hyprland.nix +++ b/modules/greetd/hyprland.nix @@ -93,7 +93,7 @@ in { } exec-once = ${setupMonitors} - exec-once = ags -b greeter &> /tmp/ags.log; hyprctl dispatch exit + exec-once = astal -b greeter &> /tmp/astal.log; hyprctl dispatch exit '' ); }