diff --git a/system/services/locate/default.nix b/system/services/locate/default.nix index 012f9dd..4c4fd51 100644 --- a/system/services/locate/default.nix +++ b/system/services/locate/default.nix @@ -5,7 +5,7 @@ }: { services.locate = { enable = true; - locate = pkgs.plocate; + package = pkgs.plocate; localuser = null; prunePaths = lib.mkOptionDefault []; interval = "hourly"; diff --git a/user/configs/wayland/ags/ags-config/config.js b/user/configs/wayland/ags/ags-config/config.js index fdd8a0f..5e64bbe 100644 --- a/user/configs/wayland/ags/ags-config/config.js +++ b/user/configs/wayland/ags/ags-config/config.js @@ -1,191 +1,5 @@ -const { Mpris, Hyprland, SystemTray, Audio } = ags.Service; -const { execAsync } = ags.Utils; -const { Box, Button, Label, Icon, CenterBox, Stack, Window } = ags.Widget; - -const Workspaces = (monitor) => Box({ - className: 'workspaces', - connections: [[Hyprland, box => { - if (monitor == 0) { - box.children = [1,2,3].map(i => Button({ - onClicked: () => execAsync(`hyprctl dispatch workspace ${i}`), - onScrollDown: () => execAsync(`hyprctl dispatch workspace +1`), - onScrollUp: () => execAsync(`hyprctl dispatch workspace -1`), - child: Label({ label: `${i}` }), - className: Hyprland.active.workspace.id == i ? 'focused' : '', - })); - } else if (monitor == 1) { - box.children = [4,5,6].map(i => Button({ - onClicked: () => execAsync(`hyprctl dispatch workspace ${i}`), - onScrollDown: () => execAsync(`hyprctl dispatch workspace +1`), - onScrollUp: () => execAsync(`hyprctl dispatch workspace -1`), - child: Label({ label: `${i}` }), - className: Hyprland.active.workspace.id == i ? 'focused' : '', - })); - } - }]], -}); - -const WindowTitle = () => Label({ - connections: [[Hyprland, label => { - label.label = Hyprland.active.client.title || ''; - label.toggleClassName('windowTitle', label.label); - }]], -}); - -const Volume = () => Button({ - className: 'volume', - onScrollUp: () => execAsync('pamixer -i 10'), - onScrollDown: () => execAsync('pamixer -d 10'), - child: Box({ - children: [ - Stack({ - items: [ - // tuples of [string, Widget] - ['101', Icon('audio-volume-overamplified-symbolic')], - ['67', Icon('audio-volume-high-symbolic')], - ['34', Icon('audio-volume-medium-symbolic')], - ['1', Icon('audio-volume-low-symbolic')], - ['0', Icon('audio-volume-muted-symbolic')], - ], - connections: [[Audio, stack => { - if (!Audio.speaker) - return; - - if (Audio.speaker.isMuted) { - stack.shown = '0'; - return; - } - - const show = [101, 67, 34, 1, 0].find( - threshold => threshold <= Audio.speaker.volume * 100); - - stack.shown = `${show}`; - }, 'speaker-changed']], - }), - - Label({ - connections: [[Audio, label => { - if (!Audio.speaker) - return; - - label.label = ` ${Math.ceil((Audio.speaker.volume * 100) / 10) * 10}%`; // round up to nearest 10 - }, 'speaker-changed' ]], - }), - ], - }), -}); - -const Media = () => Button({ - className: 'media', - onPrimaryClick: () => Mpris.getPlayer('')?.playPause(), - onScrollUp: () => Mpris.getPlayer('')?.previous(), - onScrollDown: () => Mpris.getPlayer('')?.next(), - - child: Box({ - children: [ - Stack({ - items: [ - ['paused', Icon('media-playback-pause-symbolic')], - ['playing', Icon('media-playback-start-symbolic')], - ['stopped', Icon('media-playback-stop-symbolic')], - ], - - connections: [[Mpris, stack => { - const mpris = Mpris.getPlayer(''); - - switch (mpris.playBackStatus) { - case "Playing": - stack.shown = 'playing'; - break; - case "Paused": - stack.shown = 'paused'; - break; - default: - stack.shown = 'stopped'; - } - }]], - }), - - Label({ - connections: [[Mpris, label => { - const mpris = Mpris.getPlayer(''); - if (!mpris || mpris.playBackStatus == "Stopped") - label.label = ' Stopped'; - else - label.label = ` ${mpris.trackArtists.join(', ')} - ${mpris.trackTitle}`; - }]], - }), - ], - }), -}) - -const SysTray = () => Box({ - className: 'tray', - connections: [[SystemTray, box => { - box.children = SystemTray.items.map(item => Button({ - className: 'tray-icon', - child: Icon(), - onPrimaryClick: (_, event) => item.activate(event), - onSecondaryClick: (_, event) => item.openMenu(event), - connections: [[item, button => { - button.child.icon = item.icon; - button.tooltipMarkup = item.tooltipMarkup; - }]], - })); - }]], -}); - -const Clock = () => Box({ - className: 'date', - children: [ - Icon({ - icon: 'x-office-calendar-symbolic', - }), - - Label({ - connections: [ - [1000, label => execAsync(['date', '+%a %d, %B %H:%M']) - .then(date => label.label = ' ' + date).catch(console.error)], - ], - }), - ], -}); - -const Left = (monitor) => Box({ - children: [ - Workspaces(monitor), - WindowTitle(), - ], -}); - -const Center = () => Box({ - children: [ - Volume(), - Media(), - ], -}); - - -const Right = () => Box({ - halign: 'end', - children: [ - SysTray(), - Clock(), - ], -}); - -const Bar = ({ monitor } = {}) => Window({ - name: `bar-${monitor}`, // name has to be unique - className: 'bar', - monitor, - anchor: ['top', 'left', 'right'], - exclusive: true, - child: CenterBox({ - startWidget: Left(`${monitor}`), - centerWidget: Center(), - endWidget: Right(), - }), -}) +import Panel from './js/panel/panel.js'; +import VolumeOSD from './js/volume_osd/volosd.js'; const scss = ags.App.configDir + '/style.scss'; const css = '/tmp/style-ags.css'; @@ -194,7 +8,9 @@ ags.Utils.exec(`sassc ${scss} ${css}`); export default { style: css, windows: [ - Bar({monitor: 0}), - Bar({monitor: 1}), + Panel(0), + Panel(1), + + // VolumeOSD(), ], }; diff --git a/user/configs/wayland/ags/ags-config/js/panel/panel.js b/user/configs/wayland/ags/ags-config/js/panel/panel.js new file mode 100644 index 0000000..972377c --- /dev/null +++ b/user/configs/wayland/ags/ags-config/js/panel/panel.js @@ -0,0 +1,44 @@ +import Workspaces from './widgets/workspaces.js'; +import WindowTitle from './widgets/windowTitle.js'; +// +import Volume from './widgets/volume.js'; +import Mpris from './widgets/mpris.js' +// +import SysTray from './widgets/sysTray.js'; +import Clock from './widgets/clock.js'; + +const Left = monitor => ags.Widget.Box({ + children: [ + Workspaces(monitor), + WindowTitle(), + ], +}); + +const Center = () => ags.Widget.Box({ + children: [ + Volume(), + Mpris('mpd') + ], +}); + +const Right = () => ags.Widget.Box({ + halign: 'end', + children: [ + SysTray(), + Clock(), + ], +}); + +export default monitor => ags.Widget.Window({ + name: `bar-${monitor}`, // name has to be unique + className: 'bar', + monitor, + anchor: ['top', 'left', 'right'], + exclusive: true, + child: ags.Widget.CenterBox({ + startWidget: Left(`${monitor}`), + centerWidget: Center(), + endWidget: Right(), + }), +}) + diff --git a/user/configs/wayland/ags/ags-config/js/panel/widgets/clock.js b/user/configs/wayland/ags/ags-config/js/panel/widgets/clock.js new file mode 100644 index 0000000..1fc08dc --- /dev/null +++ b/user/configs/wayland/ags/ags-config/js/panel/widgets/clock.js @@ -0,0 +1,16 @@ +export default () => ags.Widget.Box({ + className: 'date', + children: [ + ags.Widget.Icon({ + icon: 'x-office-calendar-symbolic', + }), + + ags.Widget.Label({ + connections: [ + [1000, label => ags.Utils.execAsync(['date', '+%a %d, %B %H:%M']) + .then(date => label.label = ' ' + date).catch(console.error)], + ], + }), + ], +}); + 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 new file mode 100644 index 0000000..024825c --- /dev/null +++ b/user/configs/wayland/ags/ags-config/js/panel/widgets/mpris.js @@ -0,0 +1,45 @@ +export default player => ags.Widget.Button({ + className: 'media', + onPrimaryClick: () => ags.Service.Mpris.getPlayer(player)?.playPause(), + onScrollUp: () => ags.Service.Mpris.getPlayer(player)?.previous(), + onScrollDown: () => ags.Service.Mpris.getPlayer(player)?.next(), + + child: ags.Widget.Box({ + children: [ + ags.Widget.Stack({ + items: [ + ['paused', ags.Widget.Icon('media-playback-pause-symbolic')], + ['playing', ags.Widget.Icon('media-playback-start-symbolic')], + ['stopped', ags.Widget.Icon('media-playback-stop-symbolic')], + ], + + connections: [[ags.Service.Mpris, statusIcon => { + const mpris = ags.Service.Mpris.getPlayer(player); + + switch (mpris.playBackStatus) { + case "Playing": + statusIcon.shown = 'playing'; + break; + case "Paused": + statusIcon.shown = 'paused'; + break; + default: + statusIcon.shown = 'stopped'; + } + }]], + }), + + ags.Widget.Label({ + connections: [[ags.Service.Mpris, label => { + const mpris = ags.Service.Mpris.getPlayer(player); + if (!mpris || mpris.playBackStatus == "Stopped") + label.label = ' Stopped'; + else + label.label = ` ${mpris.trackArtists.join(', ')} - ${mpris.trackTitle}`; + }]], + }), + ], + }), +}) + + 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 new file mode 100644 index 0000000..fdbb13a --- /dev/null +++ b/user/configs/wayland/ags/ags-config/js/panel/widgets/sysTray.js @@ -0,0 +1,17 @@ +export default () => ags.Widget.Box({ + className: 'tray', + connections: [[ags.Service.SystemTray, box => { + box.children = ags.Service.SystemTray.items.map(item => ags.Widget.Button({ + className: 'tray-icon', + child: ags.Widget.Icon(), + onPrimaryClick: (_, event) => item.activate(event), + onSecondaryClick: (_, event) => item.openMenu(event), + connections: [[item, button => { + button.child.icon = item.icon; + button.tooltipMarkup = item.tooltipMarkup; + }]], + })); + }]], +}); + + diff --git a/user/configs/wayland/ags/ags-config/js/panel/widgets/volume.js b/user/configs/wayland/ags/ags-config/js/panel/widgets/volume.js new file mode 100644 index 0000000..ee87f85 --- /dev/null +++ b/user/configs/wayland/ags/ags-config/js/panel/widgets/volume.js @@ -0,0 +1,44 @@ +export default () => ags.Widget.Button({ + className: 'volume', + onScrollUp: () => ags.Utils.execAsync('pamixer -i 10'), + onScrollDown: () => ags.Utils.execAsync('pamixer -d 10'), + child: ags.Widget.Box({ + children: [ + ags.Widget.Stack({ + items: [ + // tuples of [string, Widget] + ['101', ags.Widget.Icon('audio-volume-overamplified-symbolic')], + ['67', ags.Widget.Icon('audio-volume-high-symbolic')], + ['34', ags.Widget.Icon('audio-volume-medium-symbolic')], + ['1', ags.Widget.Icon('audio-volume-low-symbolic')], + ['0', ags.Widget.Icon('audio-volume-muted-symbolic')], + ], + connections: [[ags.Service.Audio, stack => { + if (!ags.Service.Audio.speaker) + return; + + if (ags.Service.Audio.speaker.isMuted) { + stack.shown = '0'; + return; + } + + const show = [101, 67, 34, 1, 0].find( + threshold => threshold <= ags.Service.Audio.speaker.volume * 100); + + stack.shown = `${show}`; + }, 'speaker-changed']], + }), + + ags.Widget.Label({ + connections: [[ags.Service.Audio, label => { + if (!ags.Service.Audio.speaker) + return; + + label.label = ` ${Math.ceil((ags.Service.Audio.speaker.volume * 100) / 10) * 10}%`; // round up to nearest 10 + }, 'speaker-changed' ]], + }), + ], + }), +}); + + diff --git a/user/configs/wayland/ags/ags-config/js/panel/widgets/windowTitle.js b/user/configs/wayland/ags/ags-config/js/panel/widgets/windowTitle.js new file mode 100644 index 0000000..8b8a8fc --- /dev/null +++ b/user/configs/wayland/ags/ags-config/js/panel/widgets/windowTitle.js @@ -0,0 +1,8 @@ +export default () => ags.Widget.Label({ + connections: [[ags.Service.Hyprland, label => { + label.label = ags.Service.Hyprland.active.client.title || ''; + label.toggleClassName('windowTitle', label.label); + }]], +}); + + diff --git a/user/configs/wayland/ags/ags-config/js/panel/widgets/workspaces.js b/user/configs/wayland/ags/ags-config/js/panel/widgets/workspaces.js new file mode 100644 index 0000000..b89fb47 --- /dev/null +++ b/user/configs/wayland/ags/ags-config/js/panel/widgets/workspaces.js @@ -0,0 +1,24 @@ +export default monitor => ags.Widget.Box({ + className: 'workspaces', + connections: [[ags.Service.Hyprland, box => { + if (monitor == 0) { + box.children = [1,2,3].map(i => ags.Widget.Button({ + onClicked: () => ags.Utils.execAsync(`hyprctl dispatch workspace ${i}`), + onScrollDown: () => ags.Utils.execAsync(`hyprctl dispatch workspace +1`), + onScrollUp: () => ags.Utils.execAsync(`hyprctl dispatch workspace -1`), + child: ags.Widget.Label({ label: `${i}` }), + className: ags.Service.Hyprland.active.workspace.id == i ? 'focused' : '', + })); + } else if (monitor == 1) { + box.children = [4,5,6].map(i => ags.Widget.Button({ + onClicked: () => ags.Utils.execAsync(`hyprctl dispatch workspace ${i}`), + onScrollDown: () => ags.Utils.execAsync(`hyprctl dispatch workspace +1`), + onScrollUp: () => ags.Utils.execAsync(`hyprctl dispatch workspace -1`), + child: ags.Widget.Label({ label: `${i}` }), + className: ags.Service.Hyprland.active.workspace.id == i ? 'focused' : '', + })); + } + }]], +}); + + diff --git a/user/configs/wayland/ags/ags-config/js/volume_osd/volosd.js b/user/configs/wayland/ags/ags-config/js/volume_osd/volosd.js new file mode 100644 index 0000000..4349da6 --- /dev/null +++ b/user/configs/wayland/ags/ags-config/js/volume_osd/volosd.js @@ -0,0 +1,10 @@ +export default () => ags.Widget.Window({ + name: `volume-osd`, + className: `osd`, + monitor: null, + focusable: false, + anchor: [ 'center' ], + popup: true, + + child: ags.Widget.Label('hello world'), +}) diff --git a/user/configs/wayland/ags/ags-config/scss/panel.scss b/user/configs/wayland/ags/ags-config/scss/panel.scss new file mode 100644 index 0000000..618f99b --- /dev/null +++ b/user/configs/wayland/ags/ags-config/scss/panel.scss @@ -0,0 +1,80 @@ +@import './themes/gruvbox.scss'; + +* { + min-height: unset; +} + +.bar { + min-height: 33px; + font-family: "JetBrainsMono Nerd Font"; + font-size: 12px; + background-color: $bg; + color: $fg; +} + +.workspaces { + background-color: $box-bg; + border-radius: $box-border-radius; + margin: 5px 0px 5px 10px; + font-size: 0px; +} + +.workspaces button { + border-radius: 0; + background-color: $wsbg; + font-size: 10px; +} + +.workspaces button.focused { + border-radius: 0px; + background-color: $activewsbg; +} + +.workspaces button:first-child { + border-radius: $box-border-radius 0px 0px $box-border-radius; +} + +.workspaces button:last-child { + border-radius: 0px $box-border-radius $box-border-radius 0px; +} + +.windowTitle { + background-color: $box-bg; + border-radius: $box-border-radius; + padding: 0px 10px 0px 10px; + margin: 5px 0px 5px 10px; +} + +.volume { + background-color: $box-bg; + border-radius: $box-border-radius; + padding: 0px 10px 0px 10px; + margin: 5px 5px 5px 0px; +} + +.media { + background-color: $box-bg; + border-radius: $box-border-radius; + padding: 0px 10px 0px 10px; + margin: 5px 10px 5px 0px; +} + +.date { + background-color: $box-bg; + padding: 0px 10px 0px 10px; + border-radius: $box-border-radius; + margin: 5px 10px 5px 0px; +}; + +.tray { + background-color: $box-bg; + padding: 0px 10px 0px 10px; + border-radius: $box-border-radius; + margin: 5px 10px 5px 0px; +} + +.tray-icon { + font-size: 18px; + background-color: $box-bg; + padding: 2px; +} diff --git a/user/configs/wayland/ags/ags-config/scss/themes/gruvbox.scss b/user/configs/wayland/ags/ags-config/scss/themes/gruvbox.scss new file mode 100644 index 0000000..a8b2a33 --- /dev/null +++ b/user/configs/wayland/ags/ags-config/scss/themes/gruvbox.scss @@ -0,0 +1,7 @@ +$bg: rgba(40,40,40,0.8); +$fg: rgb(235,219,178); +$wsfg: rgb(235,219,178); +$wsbg: rgb(60,56,54); +$activewsbg: rgb(102,92,84); +$box-bg: rgb(80,73,69); +$box-border-radius: 10px; diff --git a/user/configs/wayland/ags/ags-config/style.scss b/user/configs/wayland/ags/ags-config/style.scss index a4bc974..631df5c 100644 --- a/user/configs/wayland/ags/ags-config/style.scss +++ b/user/configs/wayland/ags/ags-config/style.scss @@ -1,89 +1 @@ -$bg: rgba(40,40,40,0.8); -$fg: rgb(235,219,178); - -$wsfg: rgb(235,219,178); -$wsbg: rgb(60,56,54); -$activewsbg: rgb(102,92,84); - -$box-bg: rgb(80,73,69); - -$box-border-radius: 10px; - -* { - min-height: unset; -} - -.bar { - min-height: 33px; - font-family: "JetBrainsMono Nerd Font"; - font-size: 12px; - background-color: $bg; - color: $fg; -} - -.workspaces { - background-color: $box-bg; - border-radius: $box-border-radius; - margin: 5px 0px 5px 10px; - font-size: 0px; -} - -.workspaces button { - border-radius: 0; - background-color: $wsbg; - font-size: 10px; -} - -.workspaces button.focused { - border-radius: 0px; - background-color: $activewsbg; -} - -.workspaces button:first-child { - border-radius: $box-border-radius 0px 0px $box-border-radius; -} - -.workspaces button:last-child { - border-radius: 0px $box-border-radius $box-border-radius 0px; -} - -.windowTitle { - background-color: $box-bg; - border-radius: $box-border-radius; - padding: 0px 10px 0px 10px; - margin: 5px 0px 5px 10px; -} - -.volume { - background-color: $box-bg; - border-radius: $box-border-radius; - padding: 0px 10px 0px 10px; - margin: 5px 5px 5px 0px; -} - -.media { - background-color: $box-bg; - border-radius: $box-border-radius; - padding: 0px 10px 0px 10px; - margin: 5px 10px 5px 0px; -} - -.date { - background-color: $box-bg; - padding: 0px 10px 0px 10px; - border-radius: $box-border-radius; - margin: 5px 10px 5px 0px; -}; - -.tray { - background-color: $box-bg; - padding: 0px 10px 0px 10px; - border-radius: $box-border-radius; - margin: 5px 10px 5px 0px; -} - -.tray-icon { - font-size: 18px; - background-color: $box-bg; - padding: 2px; -} +@import './scss/panel.scss';