diff --git a/flake.nix b/flake.nix index 026052a..f7584c7 100755 --- a/flake.nix +++ b/flake.nix @@ -54,11 +54,6 @@ inputs.nixpkgs.follows = "nixpkgs"; }; - openmw-git = { - url = "gitlab:OpenMW/openmw"; - flake = false; - }; - nvim-hmts = { url = "github:calops/hmts.nvim"; flake = false; @@ -89,6 +84,9 @@ config = { allowUnfree = true; allowUnsupportedSystem = true; + permittedInsecurePackages = [ + "libxls-1.6.2" + ]; }; overlays = [ diff --git a/system/services/default.nix b/system/services/default.nix index f2e81e3..bc37060 100644 --- a/system/services/default.nix +++ b/system/services/default.nix @@ -1,4 +1,4 @@ -{pkgs, ...}: { + { imports = [ ./avahi ./locate @@ -11,18 +11,11 @@ services = { blueman.enable = true; flatpak.enable = true; - fwupd.enable = true; gnome.gnome-keyring.enable = true; gvfs.enable = true; - irqbalance.enable = true; openssh.enable = true; udisks2.enable = true; - mullvad-vpn = { - enable = true; - package = pkgs.mullvad-vpn; - }; - fstrim = { enable = true; interval = "weekly"; diff --git a/user/configs/wayland/ags/ags-config/config.js b/user/configs/wayland/ags/ags-config/config.js index 928ff40..a98bd42 100644 --- a/user/configs/wayland/ags/ags-config/config.js +++ b/user/configs/wayland/ags/ags-config/config.js @@ -2,6 +2,7 @@ import App from 'resource:///com/github/Aylur/ags/app.js' import { exec } from 'resource://com/github/Aylur/ags/utils.js' import Panel from './js/panel/panel.js'; +import { NotificationCenter, NotificationsPopupWindow } from './js/notifications/config.js'; import { forMonitors } @@ -15,5 +16,7 @@ export default { style: css, windows: [ forMonitors(Panel), + NotificationsPopupWindow(), + NotificationCenter(), ].flat(2), }; diff --git a/user/configs/wayland/ags/ags-config/js/notifications/config.js b/user/configs/wayland/ags/ags-config/js/notifications/config.js new file mode 100644 index 0000000..1399847 --- /dev/null +++ b/user/configs/wayland/ags/ags-config/js/notifications/config.js @@ -0,0 +1,42 @@ +import { + NotificationList, ClearButton, PopupList +} from './widgets.js'; +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +import App from 'resource:///com/github/Aylur/ags/app.js'; + +const Header = () => Widget.Box({ + className: 'header', + children: [ + Widget.Box({ hexpand: true }), + ClearButton(), + ], +}); + +export const NotificationCenter = () => Widget.Window({ + name: 'notification-center', + anchor: [ 'right', 'top', 'bottom'], + popup: true, + focusable: true, + child: Widget.Box({ + children: [ + Widget.EventBox({ + hexpand: true, + connections: [['button-press-event', () => + App.closeWindow('notification-center')]] + }), + Widget.Box({ + vertical: true, + children: [ + Header(), + NotificationList(), + ], + }), + ], + }), +}); + +export const NotificationsPopupWindow = () => Widget.Window({ + name: 'popup-window', + anchor: ['right', 'top'], + child: PopupList(), +}); diff --git a/user/configs/wayland/ags/ags-config/js/notifications/notification.js b/user/configs/wayland/ags/ags-config/js/notifications/notification.js new file mode 100644 index 0000000..0082cf7 --- /dev/null +++ b/user/configs/wayland/ags/ags-config/js/notifications/notification.js @@ -0,0 +1,120 @@ +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +import { lookUpIcon, timeout } from 'resource:///com/github/Aylur/ags/utils.js'; + +const NotificationIcon = ({ appEntry, appIcon, image }) => { + if (image) { + return Widget.Box({ + valign: 'start', + hexpand: false, + className: 'icon img', + style: ` + background-image: url("${image}"); + background-size: contain; + background-repeat: no-repeat; + background-position: center; + min-width: 78px; + min-height: 78px; + `, + }); + } + + let icon = 'dialog-information-symbolic'; + if (lookUpIcon(appIcon)) + icon = appIcon; + + if (lookUpIcon(appEntry)) + icon = appEntry; + + return Widget.Box({ + valign: 'start', + hexpand: false, + className: 'icon', + style: ` + min-width: 78px; + min-height: 78px; + `, + children: [Widget.Icon({ + icon, size: 58, + halign: 'center', hexpand: true, + valign: 'center', vexpand: true, + })], + }); +}; + +export const Notification = n => Widget.EventBox({ + className: `notification ${n.urgency}`, + onPrimaryClick: () => n.dismiss(), + properties: [['hovered', false]], + onHover: self => { + if (self._hovered) + return; + + // if there are action buttons and they are hovered + // EventBox onHoverLost will fire off immediately, + // so to prevent this we delay it + timeout(300, () => self._hovered = true); + }, + onHoverLost: self => { + if (!self._hovered) + return; + + self._hovered = false; + n.dismiss(); + }, + vexpand: false, + child: Widget.Box({ + vertical: true, + children: [ + Widget.Box({ + children: [ + NotificationIcon(n), + Widget.Box({ + hexpand: true, + vertical: true, + children: [ + Widget.Box({ + children: [ + Widget.Label({ + className: 'title', + xalign: 0, + justification: 'left', + hexpand: true, + maxWidthChars: 24, + truncate: 'end', + wrap: true, + label: n.summary, + useMarkup: true, + }), + Widget.Button({ + className: 'close-button', + valign: 'start', + child: Widget.Icon('window-close-symbolic'), + onClicked: n.close.bind(n), + }), + ], + }), + Widget.Label({ + className: 'description', + hexpand: true, + useMarkup: true, + xalign: 0, + justification: 'left', + label: n.body, + wrap: true, + }), + ], + }), + ], + }), + Widget.Box({ + className: 'actions', + children: n.actions.map(({ id, label }) => Widget.Button({ + className: 'action-button', + onClicked: () => n.invoke(id), + hexpand: true, + child: Widget.Label(label), + })), + }), + ], + }), +}); diff --git a/user/configs/wayland/ags/ags-config/js/notifications/widgets.js b/user/configs/wayland/ags/ags-config/js/notifications/widgets.js new file mode 100644 index 0000000..c79bf2a --- /dev/null +++ b/user/configs/wayland/ags/ags-config/js/notifications/widgets.js @@ -0,0 +1,68 @@ +import { Notification } from './notification.js'; +import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js'; +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; + +const List = () => Widget.Box({ + vertical: true, + vexpand: true, + connections: [[Notifications, self => { + self.children = Notifications.notifications + .reverse() + .map(Notification); + + self.visible = Notifications.notifications.length > 0; + }]], +}); + +const Placeholder = () => Widget.Box({ + className: 'placeholder', + vertical: true, + vexpand: true, + valign: 'center', + children: [ + Widget.Icon('notifications-disabled-symbolic'), + Widget.Label('Your inbox is empty'), + ], + binds: [ + ['visible', Notifications, 'notifications', n => n.length === 0], + ], +}); + +export const NotificationList = () => Widget.Scrollable({ + hscroll: 'never', + vscroll: 'automatic', + child: Widget.Box({ + className: 'list', + vertical: true, + children: [ + List(), + Placeholder(), + ], + }), +}); + +export const ClearButton = () => Widget.Button({ + onClicked: () => Notifications.clear(), + binds: [ + ['sensitive', Notifications, 'notifications', n => n.length > 0], + ], + child: Widget.Box({ + children: [ + Widget.Label('Clear'), + Widget.Icon({ + binds: [ + ['icon', Notifications, 'notifications', n => + `user-trash-${n.length > 0 ? 'full-' : ''}symbolic`], + ], + }), + ], + }), +}); + +export const PopupList = () => Widget.Box({ + className: 'list', + style: 'padding: 1px;', // so it shows up + vertical: true, + binds: [['children', Notifications, 'popups', + popups => popups.map(Notification)]], +}); diff --git a/user/configs/wayland/ags/ags-config/js/panel/panel.js b/user/configs/wayland/ags/ags-config/js/panel/panel.js index 92402f9..491027a 100644 --- a/user/configs/wayland/ags/ags-config/js/panel/panel.js +++ b/user/configs/wayland/ags/ags-config/js/panel/panel.js @@ -17,14 +17,16 @@ const Left = monitor => Box({ const Center = () => Box({ children: [ - Volume(), Mpris('mpd') + Volume(), + Mpris('mpd'), ], }); const Right = () => Box({ halign: 'end', children: [ - SysTray(), Clock(), + SysTray(), + Clock(), ], }); diff --git a/user/configs/wayland/ags/ags-config/js/panel/widgets/mpris.js b/user/configs/wayland/ags/ags-config/js/panel/widgets/mpris.js index 15cbeff..053b1bd 100644 --- a/user/configs/wayland/ags/ags-config/js/panel/widgets/mpris.js +++ b/user/configs/wayland/ags/ags-config/js/panel/widgets/mpris.js @@ -2,7 +2,7 @@ import { Box, Button, Icon, Label, Stack } from 'resource:///com/github/Aylur/ag import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js'; export default player => Button({ - className: 'media', + className: 'mpris', onPrimaryClick: () => Mpris.getPlayer(player)?.playPause(), onScrollUp: () => Mpris.getPlayer(player)?.previous(), onScrollDown: () => Mpris.getPlayer(player)?.next(), diff --git a/user/configs/wayland/ags/ags-config/js/panel/widgets/sysTray.js b/user/configs/wayland/ags/ags-config/js/panel/widgets/sysTray.js index a7c9d9c..339df3e 100644 --- a/user/configs/wayland/ags/ags-config/js/panel/widgets/sysTray.js +++ b/user/configs/wayland/ags/ags-config/js/panel/widgets/sysTray.js @@ -7,7 +7,7 @@ export default () => Box({ [SystemTray, box => { box.children = SystemTray.items.map(item => Button({ className: 'tray-icons', - child: Icon(), + child: Icon({ binds: [['icon', item, 'icon']] }), onPrimaryClick: (_, event) => item.activate(event), onSecondaryClick: (_, event) => item.openMenu(event), connections: [ diff --git a/user/configs/wayland/ags/ags-config/notify-test.scss b/user/configs/wayland/ags/ags-config/notify-test.scss new file mode 100644 index 0000000..8e463cd --- /dev/null +++ b/user/configs/wayland/ags/ags-config/notify-test.scss @@ -0,0 +1,97 @@ +/* Assuming Adwaita-dark as Gtk theme */ + +#popup-window { + background-color: transparent; +} + +#notification-center { + background-color: #232323; +} + +#popup-window .notification > * { + box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.5); +} + +#popup-window *, +#notification-center *{ + outline: none; + color: white; +} + +button { + border: none; + box-shadow: none; + border-radius: 7px; + background-color: rgba(255,255,255, 0.1); +} + +button:hover { + background-color: rgba(255,255,255, 0.2); +} + +button:active { + background-color: rgba(255,255,255, 0.3); +} + +.notification > * { + margin: 8px; + padding: 8px; + border-radius: 15px; + background-color: #141414; +} + +.notification .icon { + border-radius: 7px; + margin-right: 8px; +} + +.notification .close-button { + padding: 0; + margin: 0; + min-height: 1.4em; + min-width: 1.4em; + border-radius: 1em; +} + +.notification .title { + font-size: 1.1em; + color: white; +} + +.notification .description { + color: rgba(255, 255, 255, 0.7); +} + +.list { + margin: 8px; + min-width: 380px; +} + +.action-button { + margin: 0 4px; +} + +.action-button:first-child { + margin-left: 0; +} + +.action-button:last-child { + margin-right: 0; +} + +.action-button:last-child:first-child { + margin: 0; +} + +.header { + padding: 8px; + border-bottom: 1px solid rgba(255, 255, 255, 0.2); +} + +.placeholder image { + font-size: 8em; +} + +.placeholder label { + font-size: 1.4em; +} diff --git a/user/configs/wayland/ags/ags-config/scss/panel/widgets/mpris.scss b/user/configs/wayland/ags/ags-config/scss/panel/widgets/mpris.scss index 9da5b95..c3e7305 100644 --- a/user/configs/wayland/ags/ags-config/scss/panel/widgets/mpris.scss +++ b/user/configs/wayland/ags/ags-config/scss/panel/widgets/mpris.scss @@ -1,4 +1,4 @@ -.media { +.mpris { background-color: $box-bg; border-radius: $box-border-radius; padding: 0px 10px 0px 10px; diff --git a/user/configs/wayland/ags/ags-config/style.scss b/user/configs/wayland/ags/ags-config/style.scss index df8bfaa..ee78a07 100644 --- a/user/configs/wayland/ags/ags-config/style.scss +++ b/user/configs/wayland/ags/ags-config/style.scss @@ -8,6 +8,8 @@ @import './scss/panel/widgets/clock.scss'; @import './scss/panel/widgets/sysTray.scss'; +@import './notify-test.scss'; + * { min-height: unset; diff --git a/user/configs/wayland/hyprland/default.nix b/user/configs/wayland/hyprland/default.nix index 08b77af..24f528c 100755 --- a/user/configs/wayland/hyprland/default.nix +++ b/user/configs/wayland/hyprland/default.nix @@ -67,13 +67,13 @@ in { monitor=${leftMonitor.display}, ${leftMonitor.res}, ${leftMonitor.pos}, 1 monitor=${rightMonitor.display}, ${rightMonitor.res}, ${rightMonitor.pos}, 1 - workspace = 1, monitor:${rightMonitor.display} - workspace = 2, monitor:${rightMonitor.display} - workspace = 3, monitor:${rightMonitor.display} + workspace = 1, monitor:${rightMonitor.display}, persistent:true + workspace = 2, monitor:${rightMonitor.display}, persistent:true + workspace = 3, monitor:${rightMonitor.display}, persistent:true - workspace = 4, monitor:${leftMonitor.display} - workspace = 5, monitor:${leftMonitor.display} - workspace = 6, monitor:${leftMonitor.display} + workspace = 4, monitor:${leftMonitor.display}, persistent:true + workspace = 5, monitor:${leftMonitor.display}, persistent:true + workspace = 6, monitor:${leftMonitor.display}, persistent:true input { kb_layout = us @@ -119,9 +119,9 @@ in { } drop_shadow = yes - shadow_range = 8 - shadow_render_power = 1 - col.shadow = rgba(282828ff) + shadow_range = 30 + shadow_render_power = 3 + col.shadow = rgba(1a1a1aee) } animations { diff --git a/user/configs/wayland/mako/default.nix b/user/configs/wayland/mako/default.nix index ece8d7e..ff14f04 100755 --- a/user/configs/wayland/mako/default.nix +++ b/user/configs/wayland/mako/default.nix @@ -4,7 +4,7 @@ ... }: { services.mako = { - enable = true; + enable = false; anchor = "top-right"; defaultTimeout = 5000; diff --git a/user/home.nix b/user/home.nix index c1f10cf..44bb889 100755 --- a/user/home.nix +++ b/user/home.nix @@ -59,6 +59,7 @@ pulsemixer qbittorrent qt5ct + ranger samba sc-im signal-desktop