diff --git a/modules/ags/config/widgets/bar/_index.scss b/modules/ags/config/widgets/bar/_index.scss index 7bdbcd34..7eaec5e6 100644 --- a/modules/ags/config/widgets/bar/_index.scss +++ b/modules/ags/config/widgets/bar/_index.scss @@ -20,6 +20,8 @@ } &.bluetooth icon, + &.heart-toggle label, + &.keyboard icon, &.network icon, &.tablet-mode icon { min-width: 30px; diff --git a/modules/ags/config/widgets/bar/items/heart.tsx b/modules/ags/config/widgets/bar/items/heart.tsx new file mode 100644 index 00000000..92c2d52b --- /dev/null +++ b/modules/ags/config/widgets/bar/items/heart.tsx @@ -0,0 +1,29 @@ +import { Variable } from 'astal'; + +import Persist from '../../misc/persist'; + +const HeartState = Variable(''); + +Persist({ + name: 'heart', + variable: HeartState, + condition: '', + whenFalse: '󰣐', +}); + + +export default () => ( + +); diff --git a/modules/ags/config/widgets/bar/items/keyboard-layout.tsx b/modules/ags/config/widgets/bar/items/keyboard-layout.tsx new file mode 100644 index 00000000..3b71f009 --- /dev/null +++ b/modules/ags/config/widgets/bar/items/keyboard-layout.tsx @@ -0,0 +1,87 @@ +import { Variable } from 'astal'; +import { Label } from 'astal/gtk3/widget'; + +import AstalHyprland from 'gi://AstalHyprland'; + +import { hyprMessage } from '../../../lib'; +import { Gtk } from 'astal/gtk3'; + +/* Types */ +interface Keyboard { + address: string + name: string + rules: string + model: string + layout: string + variant: string + options: string + active_keymap: string + main: boolean +} + + +const DEFAULT_KB = 'at-translated-set-2-keyboard'; + +export default () => { + const Hovered = Variable(false); + + const hyprland = AstalHyprland.get_default(); + + const getKbdLayout = (self: Label, _: string, layout?: string) => { + if (layout) { + if (layout === 'error') { + return; + } + + const shortName = layout.match(/\(([A-Za-z]+)\)/); + + self.label = shortName ? shortName[1] : layout; + } + else { + // At launch, kb layout is undefined + hyprMessage('j/devices').then((obj) => { + const keyboards = Array.from(JSON.parse(obj) + .keyboards) as Keyboard[]; + const kb = keyboards.find((v) => v.name === DEFAULT_KB); + + if (kb) { + layout = kb.active_keymap; + + const shortName = layout + .match(/\(([A-Za-z]+)\)/); + + self.label = shortName ? shortName[1] : layout; + } + else { + self.label = 'None'; + } + }).catch(print); + } + }; + + return ( + + ); +}; diff --git a/modules/ags/config/widgets/bar/wim.tsx b/modules/ags/config/widgets/bar/wim.tsx index e6846c0f..65c9c95a 100644 --- a/modules/ags/config/widgets/bar/wim.tsx +++ b/modules/ags/config/widgets/bar/wim.tsx @@ -7,6 +7,8 @@ import Bluetooth from './items/bluetooth'; import Brightness from './items/brightness'; import Clock from './items/clock'; import CurrentClient from './items/current-client'; +import Heart from './items/heart'; +import Keyboard from './items/keyboard-layout'; import Network from './items/network'; import NotifButton from './items/notif-button'; import SysTray from './items/tray'; @@ -52,6 +54,10 @@ export default () => ( /> + + + + @@ -70,6 +76,10 @@ export default () => ( + + + + diff --git a/modules/ags/config/widgets/misc/persist.ts b/modules/ags/config/widgets/misc/persist.ts new file mode 100644 index 00000000..dd22f703 --- /dev/null +++ b/modules/ags/config/widgets/misc/persist.ts @@ -0,0 +1,49 @@ +import { execAsync, readFileAsync, timeout, GLib, type Variable } from 'astal'; + +const { get_home_dir } = GLib; + + +export default ({ + name, + variable, + condition = true, + whenTrue = condition, + whenFalse = false, +}: { + name: string + variable: Variable + condition?: boolean | string + whenTrue?: boolean | string + whenFalse?: boolean | string +}) => { + const cacheFile = `${get_home_dir()}/.cache/ags/.${name}`; + + const stateCmd = () => ['bash', '-c', + `echo ${variable.get() === condition} > ${cacheFile}`]; + + const monitorState = () => { + variable.subscribe(() => { + execAsync(stateCmd()).catch(print); + }); + }; + + readFileAsync(cacheFile) + .then((content) => { + // JSON.parse was the only way I found to reliably + // convert a string of 'true' or 'false' into a bool + const value = (JSON.parse(content) ? whenTrue : whenFalse) as T; + + variable.set(value); + + timeout(1000, () => { + monitorState(); + }); + }) + .catch(() => { + execAsync(stateCmd()) + .then(() => { + monitorState(); + }) + .catch(print); + }); +}; diff --git a/modules/ags/v1/config/scss/quick-settings.scss b/modules/ags/v1/config/scss/quick-settings.scss deleted file mode 100644 index 22a7386b..00000000 --- a/modules/ags/v1/config/scss/quick-settings.scss +++ /dev/null @@ -1,184 +0,0 @@ -.quick-settings { - font-size: 30px; - min-width: 500px; - padding: 0; - background-color: $bg; - border-radius: 30px 0 30px 30px; - border: 2px solid $contrast-bg; -} - -.title { - font-size: 22px; - margin-top: 30px; -} - -.grid-label { - font-size: 30px; - margin-left: 15px; - margin-right: 10px; - min-width: 50px; -} - -.scrolled-indicator { - margin: 5px 0; -} - -.menu { - margin: 10px; - padding: 0; - border: 1.5px solid $contrast-bg; - border-radius: 10px; - font-size: 12px; - - scrolledwindow { - padding: 3px; - } - - row { - padding: 0; - margin: 0; - } - - .menu-item { - margin: 5px; - - label { - font-size: 16px; - margin-left: 5px; - } - - image { - font-size: 20px; - } - } -} - -.sub-label { - font-size: 14px; - padding: 3px; - border: 2px solid $contrast-bg; - border-radius: 10px 20px 20px 10px; - min-width: 106px; - background: #1b1b1b; - margin-top: 5px; -} - -.grid-chev { - margin-left: 10px; - margin-right: 12px; - font-size: 25px; - - transition: -gtk-icon-transform 0.3s ease-in-out; -} - -.button-grid { - font-size: 10px; - min-width: 440px; - background-color: $bgfull; - border-top: 2px solid $contrast-bg; - border-bottom: 2px solid $contrast-bg; - border-radius: 15px; - padding: 10px 15px; -} - -.grid-button { - min-height: 65px; - min-width: 70px; -} - -.left-part { - background: #1b1b1b; - border-top-left-radius: 15px; - border-bottom-left-radius: 15px; - border-left: 2px solid $contrast-bg; - border-top: 2px solid $contrast-bg; - border-bottom: 2px solid $contrast-bg; - transition: all 0.5s ease-in-out; -} - -.right-part { - background: #1b1b1b; - border-top-right-radius: 30px; - border-bottom-right-radius: 30px; - border-right: 2px solid $contrast-bg; - border-top: 2px solid $contrast-bg; - border-bottom: 2px solid $contrast-bg; - transition: all 0.5s ease-in-out; -} - -.right-part:hover, -.right-part:active { - color: $contrast-bg; - border: 2px solid $contrast-bg; - border-top-left-radius: 7px; - border-bottom-left-radius: 7px; - transition: all 0.5s ease-in-out; -} - -.left-part:hover, -.left-part:active { - color: $contrast-bg; - border: 2px solid $contrast-bg; - border-top-right-radius: 7px; - border-bottom-right-radius: 7px; - transition: all 0.5s ease-in-out; -} - -.player { - margin-top: 6px; - min-height: 220px; - opacity: 0; -} - -.slider-box { - min-height: 100px; - min-width: 470px; - background-color: $bgfull; - border-top: 2px solid $contrast-bg; - border-bottom: 2px solid $contrast-bg; - border-radius: 15px; - margin-top: 30px; - margin-bottom: 20px; - - .slider-label { - font-size: 30px; - min-width: 40px; - margin-right: -20px; - } - - .slider { - min-height: 55px; - margin-right: -15px; - - scale { - min-width: 400px; - margin-left: 18px; - margin-right: 20px; - - highlight { - margin: 0; - background-color: #79659f; - border-radius: 2em; - } - - trough { - background-color: #363847; - border-radius: 2em; - } - - slider { - margin: -4px; - min-width: 20px; - min-height: 20px; - background: #3e4153; - border-radius: 100%; - transition: background-color 0.5s ease-in-out; - } - - slider:hover { - background-color: #303240; - transition: background-color 0.5s ease-in-out; - } - } - } -} diff --git a/modules/ags/v1/config/ts/bar/heart.ts b/modules/ags/v1/config/ts/bar/heart.ts deleted file mode 100644 index d942b5ab..00000000 --- a/modules/ags/v1/config/ts/bar/heart.ts +++ /dev/null @@ -1,26 +0,0 @@ -const { Label } = Widget; - -import CursorBox from '../../misc/cursorbox.ts'; -import Persist from '../../misc/persist.ts'; - -const HeartState = Variable(''); - -Persist({ - name: 'heart', - gobject: HeartState, - prop: 'value', - condition: '', - whenFalse: '󰣐', -}); - - -export default () => CursorBox({ - on_primary_click_release: () => { - HeartState.setValue(HeartState.value === '' ? '󰣐' : ''); - }, - - child: Label({ - class_name: 'heart-toggle', - label: HeartState.bind(), - }), -}); diff --git a/modules/ags/v1/config/ts/bar/keyboard-layout.ts b/modules/ags/v1/config/ts/bar/keyboard-layout.ts deleted file mode 100644 index 4faa2abc..00000000 --- a/modules/ags/v1/config/ts/bar/keyboard-layout.ts +++ /dev/null @@ -1,54 +0,0 @@ -const Hyprland = await Service.import('hyprland'); -const { Icon, Label } = Widget; - -import HoverRevealer from './hover-revealer.ts'; - -const DEFAULT_KB = 'at-translated-set-2-keyboard'; - -// Types -import { Keyboard, LabelGeneric } from 'global-types'; - - -const getKbdLayout = (self: LabelGeneric, _: string, layout: string) => { - if (layout) { - if (layout === 'error') { - return; - } - - const shortName = layout.match(/\(([A-Za-z]+)\)/); - - self.label = shortName ? shortName[1] : layout; - } - else { - // At launch, kb layout is undefined - Hyprland.messageAsync('j/devices').then((obj) => { - const keyboards = Array.from(JSON.parse(obj) - .keyboards) as Keyboard[]; - const kb = keyboards.find((v) => v.name === DEFAULT_KB); - - if (kb) { - layout = kb.active_keymap; - - const shortName = layout - .match(/\(([A-Za-z]+)\)/); - - self.label = shortName ? shortName[1] : layout; - } - else { - self.label = 'None'; - } - }).catch(print); - } -}; - -export default () => HoverRevealer({ - class_name: 'keyboard', - spacing: 4, - - icon: Icon({ - icon: 'input-keyboard-symbolic', - size: 20, - }), - label: Label({ css: 'font-size: 20px;' }) - .hook(Hyprland, getKbdLayout, 'keyboard-layout'), -});