Merge branch 'master' into master

This commit is contained in:
Ludovic Ortega
2024-10-22 23:28:15 +02:00
committed by GitHub
25 changed files with 425 additions and 249 deletions

View File

@@ -37,6 +37,11 @@ export const CustomModuleSettings = (): Scrollable<GtkWidget, Attribute> =>
title: 'Button Border', title: 'Button Border',
type: 'boolean', type: 'boolean',
}), }),
Option({
opt: options.bar.customModules.ram.icon,
title: 'Ram Icon',
type: 'string',
}),
Option({ Option({
opt: options.bar.customModules.ram.label, opt: options.bar.customModules.ram.label,
title: 'Show Label', title: 'Show Label',
@@ -93,6 +98,11 @@ export const CustomModuleSettings = (): Scrollable<GtkWidget, Attribute> =>
title: 'Button Border', title: 'Button Border',
type: 'boolean', type: 'boolean',
}), }),
Option({
opt: options.bar.customModules.cpu.icon,
title: 'Cpu Icon',
type: 'string',
}),
Option({ Option({
opt: options.bar.customModules.cpu.label, opt: options.bar.customModules.cpu.label,
title: 'Show Label', title: 'Show Label',
@@ -156,8 +166,7 @@ export const CustomModuleSettings = (): Scrollable<GtkWidget, Attribute> =>
Option({ Option({
opt: options.bar.customModules.storage.icon, opt: options.bar.customModules.storage.icon,
title: 'Storage Icon', title: 'Storage Icon',
type: 'enum', type: 'string',
enums: ['󰋊', '', '󱛟', '', '', ''],
}), }),
Option({ Option({
opt: options.bar.customModules.storage.label, opt: options.bar.customModules.storage.label,
@@ -225,8 +234,7 @@ export const CustomModuleSettings = (): Scrollable<GtkWidget, Attribute> =>
Option({ Option({
opt: options.bar.customModules.netstat.icon, opt: options.bar.customModules.netstat.icon,
title: 'Netstat Icon', title: 'Netstat Icon',
type: 'enum', type: 'string',
enums: ['󰖟', '󰇚', '󰕒', '󰛳', '', '󰣺', '󰖩', '', '󰈀'],
}), }),
Option({ Option({
opt: options.bar.customModules.netstat.label, opt: options.bar.customModules.netstat.label,
@@ -292,9 +300,8 @@ export const CustomModuleSettings = (): Scrollable<GtkWidget, Attribute> =>
}), }),
Option({ Option({
opt: options.bar.customModules.kbLayout.icon, opt: options.bar.customModules.kbLayout.icon,
title: 'kbLayout Icon', title: 'Keyboard Layout Icon',
type: 'enum', type: 'string',
enums: ['', '󰌌', '', '󰬴', '󰗊'],
}), }),
Option({ Option({
opt: options.bar.customModules.kbLayout.label, opt: options.bar.customModules.kbLayout.label,
@@ -357,8 +364,7 @@ export const CustomModuleSettings = (): Scrollable<GtkWidget, Attribute> =>
Option({ Option({
opt: options.bar.customModules.updates.icon, opt: options.bar.customModules.updates.icon,
title: 'Updates Icon', title: 'Updates Icon',
type: 'enum', type: 'string',
enums: ['󰚰', '󰇚', '', '󱑢', '󱑣', '󰏖', '', '󰏔', '󰏗'],
}), }),
Option({ Option({
opt: options.bar.customModules.updates.label, opt: options.bar.customModules.updates.label,
@@ -557,8 +563,7 @@ export const CustomModuleSettings = (): Scrollable<GtkWidget, Attribute> =>
Option({ Option({
opt: options.bar.customModules.power.icon, opt: options.bar.customModules.power.icon,
title: 'Power Button Icon', title: 'Power Button Icon',
type: 'enum', type: 'string',
enums: ['', '', '󰍃', '󰿅', '󰒲', '󰤄'],
}), }),
Option({ Option({
opt: options.bar.customModules.power.leftClick, opt: options.bar.customModules.power.leftClick,

View File

@@ -13,7 +13,7 @@ import { BarBoxChild } from 'lib/types/bar';
import { Attribute, Child } from 'lib/types/widget'; import { Attribute, Child } from 'lib/types/widget';
// All the user configurable options for the cpu module that are needed // All the user configurable options for the cpu module that are needed
const { label, round, leftClick, rightClick, middleClick, scrollUp, scrollDown, pollingInterval } = const { label, round, leftClick, rightClick, middleClick, scrollUp, scrollDown, pollingInterval, icon } =
options.bar.customModules.cpu; options.bar.customModules.cpu;
export const cpuUsage = Variable(0); export const cpuUsage = Variable(0);
@@ -35,7 +35,7 @@ export const Cpu = (): BarBoxChild => {
}; };
const cpuModule = module({ const cpuModule = module({
textIcon: '', textIcon: icon.bind('value'),
label: Utils.merge([cpuUsage.bind('value'), round.bind('value')], (cpuUsg, rnd) => { label: Utils.merge([cpuUsage.bind('value'), round.bind('value')], (cpuUsg, rnd) => {
return renderLabel(cpuUsg, rnd); return renderLabel(cpuUsg, rnd);
}), }),

View File

@@ -20,7 +20,8 @@ import { pollVariable } from 'customModules/PollVar';
import { Attribute, Child } from 'lib/types/widget'; import { Attribute, Child } from 'lib/types/widget';
// All the user configurable options for the ram module that are needed // All the user configurable options for the ram module that are needed
const { label, labelType, round, leftClick, rightClick, middleClick, pollingInterval } = options.bar.customModules.ram; const { label, labelType, round, leftClick, rightClick, middleClick, pollingInterval, icon } =
options.bar.customModules.ram;
const defaultRamData: GenericResourceData = { total: 0, used: 0, percentage: 0, free: 0 }; const defaultRamData: GenericResourceData = { total: 0, used: 0, percentage: 0, free: 0 };
const ramUsage = Variable<GenericResourceData>(defaultRamData); const ramUsage = Variable<GenericResourceData>(defaultRamData);
@@ -29,7 +30,7 @@ pollVariable(ramUsage, [round.bind('value')], pollingInterval.bind('value'), cal
export const Ram = (): BarBoxChild => { export const Ram = (): BarBoxChild => {
const ramModule = module({ const ramModule = module({
textIcon: '', textIcon: icon.bind('value'),
label: Utils.merge( label: Utils.merge(
[ramUsage.bind('value'), labelType.bind('value'), round.bind('value')], [ramUsage.bind('value'), labelType.bind('value'), round.bind('value')],
(rmUsg: GenericResourceData, lblTyp: ResourceLabelType, round: boolean) => { (rmUsg: GenericResourceData, lblTyp: ResourceLabelType, round: boolean) => {

View File

@@ -25,11 +25,11 @@ export const getNotificationIcon = (app_name: string, app_icon: string, app_entr
return icon; return icon;
}; };
export const closeNotifications = async (notifications: Notification[]): Promise<void> => { export const closeNotifications = async (notifications: Notification[], delay: number): Promise<void> => {
removingNotifications.value = true; removingNotifications.value = true;
for (const notif of notifications) { for (const notif of notifications) {
notif.close(); notif.close();
await new Promise((resolve) => setTimeout(resolve, 100)); await new Promise((resolve) => setTimeout(resolve, delay));
} }
removingNotifications.value = false; removingNotifications.value = false;
}; };

5
lib/types/bar.d.ts vendored
View File

@@ -36,12 +36,7 @@ export type Module = {
export type ResourceLabelType = 'used/total' | 'used' | 'percentage' | 'free'; export type ResourceLabelType = 'used/total' | 'used' | 'percentage' | 'free';
export type StorageIcon = '󰋊' | '' | '󱛟' | '' | '' | '';
export type NetstatIcon = '󰖟' | '󰇚' | '󰕒' | '󰛳' | '' | '󰣺' | '󰖩' | '' | '󰈀';
export type NetstatLabelType = 'full' | 'in' | 'out'; export type NetstatLabelType = 'full' | 'in' | 'out';
export type RateUnit = 'GiB' | 'MiB' | 'KiB' | 'auto'; export type RateUnit = 'GiB' | 'MiB' | 'KiB' | 'auto';
export type UpdatesIcon = '󰚰' | '󰇚' | '' | '󱑢' | '󱑣' | '󰏖' | '' | '󰏔' | '󰏗';
export type PowerIcon = '' | '' | '󰍃' | '󰿅' | '󰒲' | '󰤄';

View File

@@ -1,7 +1,6 @@
import { layoutMap } from 'customModules/kblayout/layouts'; import { layoutMap } from 'customModules/kblayout/layouts';
export type KbLabelType = 'layout' | 'code'; export type KbLabelType = 'layout' | 'code';
export type KbIcon = '' | '󰌌' | '' | '󰬴' | '󰗊';
export type HyprctlKeyboard = { export type HyprctlKeyboard = {
address: string; address: string;

View File

@@ -7,7 +7,7 @@ import Button from 'types/widgets/button.js';
import { Attribute, Child } from 'lib/types/widget.js'; import { Attribute, Child } from 'lib/types/widget.js';
import { runAsyncCommand, throttledScrollHandler } from 'customModules/utils.js'; import { runAsyncCommand, throttledScrollHandler } from 'customModules/utils.js';
const { label: show_label, rightClick, middleClick, scrollUp, scrollDown } = options.bar.battery; const { label: show_label, rightClick, middleClick, scrollUp, scrollDown, hideLabelWhenFull } = options.bar.battery;
const BatteryLabel = (): BarBoxChild => { const BatteryLabel = (): BarBoxChild => {
const isVis = Variable(battery.available); const isVis = Variable(battery.available);
@@ -59,17 +59,28 @@ const BatteryLabel = (): BarBoxChild => {
), ),
visible: battery.bind('available'), visible: battery.bind('available'),
tooltip_text: battery.bind('time_remaining').as((t) => t.toString()), tooltip_text: battery.bind('time_remaining').as((t) => t.toString()),
children: Utils.merge([battery.bind('available'), show_label.bind('value')], (batAvail, showLabel) => { children: Utils.merge(
[
battery.bind('available'),
show_label.bind('value'),
battery.bind('charged'),
hideLabelWhenFull.bind('value'),
],
(batAvail, showLabel, isCharged, hideWhenFull) => {
if (batAvail && showLabel) { if (batAvail && showLabel) {
return [ return [
Widget.Icon({ Widget.Icon({
class_name: 'bar-button-icon battery', class_name: 'bar-button-icon battery',
icon: batIcon, icon: batIcon,
}), }),
...(hideWhenFull && isCharged
? []
: [
Widget.Label({ Widget.Label({
class_name: 'bar-button-label battery', class_name: 'bar-button-label battery',
label: battery.bind('percent').as((p) => `${Math.floor(p)}%`), label: battery.bind('percent').as((p) => `${Math.floor(p)}%`),
}), }),
]),
]; ];
} else if (batAvail && !showLabel) { } else if (batAvail && !showLabel) {
return [ return [
@@ -81,7 +92,8 @@ const BatteryLabel = (): BarBoxChild => {
} else { } else {
return []; return [];
} }
}), },
),
setup: (self) => { setup: (self) => {
self.hook(battery, () => { self.hook(battery, () => {
if (battery.available) { if (battery.available) {

View File

@@ -7,7 +7,7 @@ import Button from 'types/widgets/button.js';
import { Attribute, Child } from 'lib/types/widget.js'; import { Attribute, Child } from 'lib/types/widget.js';
import { runAsyncCommand, throttledScrollHandler } from 'customModules/utils.js'; import { runAsyncCommand, throttledScrollHandler } from 'customModules/utils.js';
const { show_total, rightClick, middleClick, scrollUp, scrollDown } = options.bar.notifications; const { show_total, rightClick, middleClick, scrollUp, scrollDown, hideCountWhenZero } = options.bar.notifications;
const { ignore } = options.notifications; const { ignore } = options.notifications;
const notifs = await Service.import('notifications'); const notifs = await Service.import('notifications');
@@ -32,8 +32,14 @@ export const Notifications = (): BarBoxChild => {
hpack: 'start', hpack: 'start',
class_name: 'bar-notifications', class_name: 'bar-notifications',
children: Utils.merge( children: Utils.merge(
[notifs.bind('notifications'), notifs.bind('dnd'), show_total.bind('value'), ignore.bind('value')], [
(notif, dnd, showTotal, ignoredNotifs) => { notifs.bind('notifications'),
notifs.bind('dnd'),
show_total.bind('value'),
ignore.bind('value'),
hideCountWhenZero.bind('value'),
],
(notif, dnd, showTotal, ignoredNotifs, hideCountForZero) => {
const filteredNotifications = filterNotifications(notif, ignoredNotifs); const filteredNotifications = filterNotifications(notif, ignoredNotifs);
const notifIcon = Widget.Label({ const notifIcon = Widget.Label({
@@ -49,6 +55,9 @@ export const Notifications = (): BarBoxChild => {
}); });
if (showTotal) { if (showTotal) {
if (hideCountForZero && filteredNotifications.length === 0) {
return [notifIcon];
}
return [notifIcon, notifLabel]; return [notifIcon, notifLabel];
} }
return [notifIcon]; return [notifIcon];

View File

@@ -1,7 +1,7 @@
import { BoxWidget } from 'lib/types/widget'; import { BoxWidget } from 'lib/types/widget';
import options from 'options'; import options from 'options';
const { military } = options.menus.clock.time; const { military, hideSeconds } = options.menus.clock.time;
const time = Variable('', { const time = Variable('', {
poll: [1000, 'date "+%I:%M:%S"'], poll: [1000, 'date "+%I:%M:%S"'],
@@ -26,7 +26,9 @@ const TimeWidget = (): BoxWidget => {
vpack: 'center', vpack: 'center',
hpack: 'center', hpack: 'center',
class_name: 'clock-content-items', class_name: 'clock-content-items',
children: military.bind('value').as((is24hr) => { children: Utils.merge(
[military.bind('value'), hideSeconds.bind('value')],
(is24hr: boolean, hideSeconds: boolean) => {
if (!is24hr) { if (!is24hr) {
return [ return [
Widget.Box({ Widget.Box({
@@ -34,7 +36,7 @@ const TimeWidget = (): BoxWidget => {
children: [ children: [
Widget.Label({ Widget.Label({
class_name: 'clock-content-time', class_name: 'clock-content-time',
label: time.bind(), label: hideSeconds ? time.bind().as((str) => str.slice(0, -3)) : time.bind(),
}), }),
], ],
}), }),
@@ -57,12 +59,15 @@ const TimeWidget = (): BoxWidget => {
children: [ children: [
Widget.Label({ Widget.Label({
class_name: 'clock-content-time', class_name: 'clock-content-time',
label: militaryTime.bind(), label: hideSeconds
? militaryTime.bind().as((str) => str.slice(0, -3))
: militaryTime.bind(),
}), }),
], ],
}), }),
]; ];
}), },
),
}), }),
}); });
}; };

View File

@@ -8,7 +8,7 @@ import Window from 'types/widgets/window.js';
import { Attribute, Child } from 'lib/types/widget.js'; import { Attribute, Child } from 'lib/types/widget.js';
import options from 'options.js'; import options from 'options.js';
const { enabled: directoriesEnabled } = options.menus.dashboard.directories; const { controls, shortcuts, stats, directories } = options.menus.dashboard;
export default (): Window<Child, Attribute> => { export default (): Window<Child, Attribute> => {
return DropdownMenu({ return DropdownMenu({
@@ -22,21 +22,29 @@ export default (): Window<Child, Attribute> => {
Widget.Box({ Widget.Box({
class_name: 'dashboard-content-container', class_name: 'dashboard-content-container',
vertical: true, vertical: true,
children: directoriesEnabled.bind('value').as((isDirectoriesEnabled) => { children: Utils.merge(
[
controls.enabled.bind('value'),
shortcuts.enabled.bind('value'),
stats.enabled.bind('value'),
directories.enabled.bind('value'),
],
(isControlsEnabled, isShortcutsEnabled, isStatsEnabled, isDirectoriesEnabled) => {
return [ return [
Widget.Box({ Widget.Box({
class_name: 'dashboard-content-items', class_name: 'dashboard-content-items',
vertical: true, vertical: true,
children: [ children: [
Profile(), Profile(),
Shortcuts(), ...(isShortcutsEnabled ? [Shortcuts()] : []),
Controls(), ...(isControlsEnabled ? [Controls()] : []),
...(isDirectoriesEnabled ? [Directories()] : []), ...(isDirectoriesEnabled ? [Directories()] : []),
Stats(), ...(isStatsEnabled ? [Stats()] : []),
], ],
}), }),
]; ];
}), },
),
}), }),
], ],
}), }),

View File

@@ -1,12 +1,20 @@
const powerProfiles = await Service.import('powerprofiles'); const powerProfiles = await Service.import('powerprofiles');
import { PowerProfile, PowerProfileObject, PowerProfiles } from 'lib/types/powerprofiles.js'; import { PowerProfile, PowerProfileObject, PowerProfiles } from 'lib/types/powerprofiles.js';
import icons from '../../../icons/index.js';
import { BoxWidget } from 'lib/types/widget.js'; import { BoxWidget } from 'lib/types/widget.js';
import icons from '../../../icons/index.js';
import { uptime } from 'lib/variables.js';
const EnergyProfiles = (): BoxWidget => { const EnergyProfiles = (): BoxWidget => {
const isValidProfile = (profile: string): profile is PowerProfile => const isValidProfile = (profile: string): profile is PowerProfile =>
profile === 'power-saver' || profile === 'balanced' || profile === 'performance'; profile === 'power-saver' || profile === 'balanced' || profile === 'performance';
function renderUptime(curUptime: number): string {
const days = Math.floor(curUptime / (60 * 24));
const hours = Math.floor((curUptime % (60 * 24)) / 60);
const minutes = Math.floor(curUptime % 60);
return ` : ${days}d ${hours}h ${minutes}m`;
}
return Widget.Box({ return Widget.Box({
class_name: 'menu-section-container energy', class_name: 'menu-section-container energy',
vertical: true, vertical: true,
@@ -14,12 +22,19 @@ const EnergyProfiles = (): BoxWidget => {
Widget.Box({ Widget.Box({
class_name: 'menu-label-container', class_name: 'menu-label-container',
hpack: 'fill', hpack: 'fill',
child: Widget.Label({ children: [
Widget.Label({
class_name: 'menu-label', class_name: 'menu-label',
hexpand: true, hexpand: true,
hpack: 'start', hpack: 'start',
label: 'Power Profile', label: 'Power Profile',
}), }),
Widget.Label({
class_name: 'menu-label uptime',
label: uptime.bind().as(renderUptime),
tooltipText: 'Uptime',
}),
],
}), }),
Widget.Box({ Widget.Box({
class_name: 'menu-items-section', class_name: 'menu-items-section',

View File

@@ -31,6 +31,15 @@ const Wifi = (): BoxWidget => {
hpack: 'start', hpack: 'start',
label: 'Wi-Fi', label: 'Wi-Fi',
}), }),
Widget.Switch({
class_name: 'menu-switch network',
vpack: 'center',
tooltip_text: 'Toggle Wifi',
active: network.wifi.enabled,
on_activate: () => {
network.toggleWifi();
},
}),
Widget.Button({ Widget.Button({
vpack: 'center', vpack: 'center',
hpack: 'end', hpack: 'end',

View File

@@ -1,6 +1,9 @@
import { closeNotifications } from 'globals/notification'; import { closeNotifications } from 'globals/notification';
import { BoxWidget } from 'lib/types/widget'; import { BoxWidget } from 'lib/types/widget';
import { Notifications } from 'types/service/notifications'; import { Notifications } from 'types/service/notifications';
import options from 'options';
const { clearDelay } = options.notifications;
const Controls = (notifs: Notifications): BoxWidget => { const Controls = (notifs: Notifications): BoxWidget => {
return Widget.Box({ return Widget.Box({
@@ -44,13 +47,15 @@ const Controls = (notifs: Notifications): BoxWidget => {
Widget.Button({ Widget.Button({
className: 'clear-notifications-button', className: 'clear-notifications-button',
tooltip_text: 'Clear Notifications', tooltip_text: 'Clear Notifications',
on_primary_click: () => { on_primary_click: clearDelay.bind('value').as((delay) => {
return () => {
if (removingNotifications.value) { if (removingNotifications.value) {
return; return;
} }
closeNotifications(notifs.notifications); return closeNotifications(notifs.notifications, delay);
}, };
}),
child: Widget.Label({ child: Widget.Label({
class_name: removingNotifications.bind('value').as((removing: boolean) => { class_name: removingNotifications.bind('value').as((removing: boolean) => {
return removing return removing

View File

@@ -21,7 +21,7 @@ export const NotificationPager = (curPage: Variable<number>): BoxWidget => {
showPager.bind('value'), showPager.bind('value'),
], ],
(currentPage: number, dispTotal: number, _: Notification[], showPgr: boolean) => { (currentPage: number, dispTotal: number, _: Notification[], showPgr: boolean) => {
if (showPgr === false) { if (showPgr === false || (currentPage === 1 && notifs.notifications.length <= dispTotal)) {
return []; return [];
} }
return [ return [

View File

@@ -1,14 +1,6 @@
import { opt, mkOptions } from 'lib/option'; import { opt, mkOptions } from 'lib/option';
import { import { NetstatLabelType, RateUnit, ResourceLabelType } from 'lib/types/bar';
NetstatIcon, import { KbLabelType } from 'lib/types/customModules/kbLayout';
NetstatLabelType,
PowerIcon,
RateUnit,
ResourceLabelType,
StorageIcon,
UpdatesIcon,
} from 'lib/types/bar';
import { KbIcon, KbLabelType } from 'lib/types/customModules/kbLayout';
import { import {
ActiveWsIndicator, ActiveWsIndicator,
BarButtonStyles, BarButtonStyles,
@@ -528,6 +520,11 @@ const options = mkOptions(OPTIONS, {
passive: opt(colors.text), passive: opt(colors.text),
active: opt(colors.mauve), active: opt(colors.mauve),
}, },
switch: {
enabled: opt(colors.mauve),
disabled: opt(tertiary_colors.surface0),
puck: opt(secondary_colors.surface1),
},
}, },
bluetooth: { bluetooth: {
scaling: opt(100), scaling: opt(100),
@@ -907,6 +904,7 @@ const options = mkOptions(OPTIONS, {
}, },
battery: { battery: {
label: opt(true), label: opt(true),
hideLabelWhenFull: opt(false),
rightClick: opt(''), rightClick: opt(''),
middleClick: opt(''), middleClick: opt(''),
scrollUp: opt(''), scrollUp: opt(''),
@@ -936,6 +934,7 @@ const options = mkOptions(OPTIONS, {
}, },
notifications: { notifications: {
show_total: opt(false), show_total: opt(false),
hideCountWhenZero: opt(false),
rightClick: opt(''), rightClick: opt(''),
middleClick: opt(''), middleClick: opt(''),
scrollUp: opt(''), scrollUp: opt(''),
@@ -944,6 +943,7 @@ const options = mkOptions(OPTIONS, {
customModules: { customModules: {
scrollSpeed: opt(5), scrollSpeed: opt(5),
ram: { ram: {
icon: opt(''),
label: opt(true), label: opt(true),
labelType: opt<ResourceLabelType>('percentage'), labelType: opt<ResourceLabelType>('percentage'),
round: opt(true), round: opt(true),
@@ -953,6 +953,7 @@ const options = mkOptions(OPTIONS, {
middleClick: opt(''), middleClick: opt(''),
}, },
cpu: { cpu: {
icon: opt(''),
label: opt(true), label: opt(true),
round: opt(true), round: opt(true),
pollingInterval: opt(2000), pollingInterval: opt(2000),
@@ -964,7 +965,7 @@ const options = mkOptions(OPTIONS, {
}, },
storage: { storage: {
label: opt(true), label: opt(true),
icon: opt<StorageIcon>('󰋊'), icon: opt('󰋊'),
round: opt(false), round: opt(false),
labelType: opt<ResourceLabelType>('percentage'), labelType: opt<ResourceLabelType>('percentage'),
pollingInterval: opt(2000), pollingInterval: opt(2000),
@@ -975,7 +976,7 @@ const options = mkOptions(OPTIONS, {
netstat: { netstat: {
label: opt(true), label: opt(true),
networkInterface: opt(''), networkInterface: opt(''),
icon: opt<NetstatIcon>('󰖟'), icon: opt('󰖟'),
round: opt(true), round: opt(true),
labelType: opt<NetstatLabelType>('full'), labelType: opt<NetstatLabelType>('full'),
rateUnit: opt<RateUnit>('auto'), rateUnit: opt<RateUnit>('auto'),
@@ -987,7 +988,7 @@ const options = mkOptions(OPTIONS, {
kbLayout: { kbLayout: {
label: opt(true), label: opt(true),
labelType: opt<KbLabelType>('code'), labelType: opt<KbLabelType>('code'),
icon: opt<KbIcon>('󰌌'), icon: opt('󰌌'),
leftClick: opt(''), leftClick: opt(''),
rightClick: opt(''), rightClick: opt(''),
middleClick: opt(''), middleClick: opt(''),
@@ -998,7 +999,7 @@ const options = mkOptions(OPTIONS, {
updateCommand: opt('$HOME/.config/ags/scripts/checkUpdates.sh -arch'), updateCommand: opt('$HOME/.config/ags/scripts/checkUpdates.sh -arch'),
label: opt(true), label: opt(true),
padZero: opt(true), padZero: opt(true),
icon: opt<UpdatesIcon>('󰏖'), icon: opt('󰏖'),
pollingInterval: opt(1000 * 60 * 60 * 6), pollingInterval: opt(1000 * 60 * 60 * 6),
leftClick: opt(''), leftClick: opt(''),
rightClick: opt(''), rightClick: opt(''),
@@ -1029,7 +1030,7 @@ const options = mkOptions(OPTIONS, {
scrollDown: opt(''), scrollDown: opt(''),
}, },
power: { power: {
icon: opt<PowerIcon>(''), icon: opt(''),
showLabel: opt(true), showLabel: opt(true),
leftClick: opt('menu:powerdropdown'), leftClick: opt('menu:powerdropdown'),
rightClick: opt(''), rightClick: opt(''),
@@ -1064,9 +1065,14 @@ const options = mkOptions(OPTIONS, {
}, },
}, },
stats: { stats: {
enabled: opt(true),
enable_gpu: opt(false), enable_gpu: opt(false),
}, },
controls: {
enabled: opt(true),
},
shortcuts: { shortcuts: {
enabled: opt(true),
left: { left: {
shortcut1: { shortcut1: {
icon: opt('󰇩'), icon: opt('󰇩'),
@@ -1137,6 +1143,7 @@ const options = mkOptions(OPTIONS, {
clock: { clock: {
time: { time: {
military: opt(false), military: opt(false),
hideSeconds: opt(false),
}, },
weather: { weather: {
enabled: opt(true), enabled: opt(true),
@@ -1170,6 +1177,7 @@ const options = mkOptions(OPTIONS, {
active_monitor: opt(true), active_monitor: opt(true),
timeout: opt(7000), timeout: opt(7000),
cache_actions: opt(true), cache_actions: opt(true),
clearDelay: opt(100),
}, },
dummy: opt(true), dummy: opt(true),

View File

@@ -25,6 +25,10 @@
$bar-buttons-radius * 0.4, $bar-buttons-radius * 0.4,
$bar-buttons-radius $bar-buttons-radius
); );
&:last-child {
border-radius: $bar-buttons-radius;
}
} }
.bar-button-label.battery { .bar-button-label.battery {
@@ -56,3 +60,4 @@
0em 0em
); );
} }

View File

@@ -28,6 +28,10 @@
$bar-buttons-radius $bar-buttons-radius
); );
color: if($bar-buttons-monochrome, $bar-buttons-icon, $bar-buttons-notifications-icon); color: if($bar-buttons-monochrome, $bar-buttons-icon, $bar-buttons-notifications-icon);
&:last-child {
border-radius: $bar-buttons-radius;
}
} }
.bar-button-label.notifications { .bar-button-label.notifications {

View File

@@ -22,6 +22,9 @@
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-battery-card-color); background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-battery-card-color);
} }
.uptime {
font-size: 0.92em;
}
.menu-items-section { .menu-items-section {
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-battery-card-color); background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-battery-card-color);

View File

@@ -2,7 +2,7 @@
font-size: $font-size * $bar-menus-menu-network-scaling * 0.01; font-size: $font-size * $bar-menus-menu-network-scaling * 0.01;
} }
@import "./menu.scss"; @import './menu.scss';
.menu-items.network { .menu-items.network {
background: if($bar-menus-monochrome, $bar-menus-background, $bar-menus-menu-network-background-color); background: if($bar-menus-monochrome, $bar-menus-background, $bar-menus-menu-network-background-color);
@@ -72,7 +72,11 @@
} }
.active-connection { .active-connection {
color: if($bar-menus-monochrome, $bar-menus-iconbuttons-active, $bar-menus-menu-network-iconbuttons-active); color: if(
$bar-menus-monochrome,
$bar-menus-iconbuttons-active,
$bar-menus-menu-network-iconbuttons-active
);
} }
} }
@@ -140,8 +144,41 @@
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-network-card-color); background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-network-card-color);
} }
.menu-items-section { .menu-items-section {
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-network-card-color); background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-network-card-color);
} }
.menu-switch.network {
background-color: if(
$bar-menus-monochrome,
$bar-menus-switch-disabled,
$bar-menus-menu-network-switch-disabled
);
&:checked {
background: if($bar-menus-monochrome, $bar-menus-switch-enabled, $bar-menus-menu-network-switch-enabled);
}
slider {
background-color: if($bar-menus-monochrome, $bar-menus-switch-puck, $bar-menus-menu-network-switch-puck);
}
&:hover {
trough {
background: if(
$bar-menus-monochrome,
$bar-menus-switch-disabled,
$bar-menus-menu-network-switch-disabled
);
}
slider {
background: if($bar-menus-monochrome, $bar-menus-switch-puck, $bar-menus-menu-network-switch-puck);
}
}
&:active {
background: if($bar-menus-monochrome, $bar-menus-switch-enabled, $bar-menus-menu-network-switch-enabled);
}
}
} }

View File

@@ -559,6 +559,11 @@ export const BarSettings = (): Scrollable<Gtk.Widget, Gtk.Widget> => {
title: 'Show Battery Percentage', title: 'Show Battery Percentage',
type: 'boolean', type: 'boolean',
}), }),
Option({
opt: options.bar.battery.hideLabelWhenFull,
title: 'Hide Battery Percentage When Full',
type: 'boolean',
}),
Option({ Option({
opt: options.theme.bar.buttons.battery.spacing, opt: options.theme.bar.buttons.battery.spacing,
title: 'Inner Spacing', title: 'Inner Spacing',
@@ -738,6 +743,12 @@ export const BarSettings = (): Scrollable<Gtk.Widget, Gtk.Widget> => {
title: 'Show Total # of notifications', title: 'Show Total # of notifications',
type: 'boolean', type: 'boolean',
}), }),
Option({
opt: options.bar.notifications.hideCountWhenZero,
title: 'Auto Hide Label',
subtitle: 'Hide Total # of notifications when zero',
type: 'boolean',
}),
Option({ Option({
opt: options.theme.bar.buttons.notifications.spacing, opt: options.theme.bar.buttons.notifications.spacing,
title: 'Inner Spacing', title: 'Inner Spacing',

View File

@@ -14,6 +14,7 @@ export const ClockMenuSettings = (): Scrollable<Child, Attribute> => {
children: [ children: [
Header('Time'), Header('Time'),
Option({ opt: options.menus.clock.time.military, title: 'Use 24hr time', type: 'boolean' }), Option({ opt: options.menus.clock.time.military, title: 'Use 24hr time', type: 'boolean' }),
Option({ opt: options.menus.clock.time.hideSeconds, title: 'Hide seconds', type: 'boolean' }),
Header('Weather'), Header('Weather'),
Option({ opt: options.menus.clock.weather.enabled, title: 'Enabled', type: 'boolean' }), Option({ opt: options.menus.clock.weather.enabled, title: 'Enabled', type: 'boolean' }),

View File

@@ -43,16 +43,18 @@ export const DashboardMenuSettings = (): Scrollable<Child, Attribute> => {
Option({ opt: options.menus.dashboard.powermenu.reboot, title: 'Reboot Command', type: 'string' }), Option({ opt: options.menus.dashboard.powermenu.reboot, title: 'Reboot Command', type: 'string' }),
Option({ opt: options.menus.dashboard.powermenu.logout, title: 'Logout Command', type: 'string' }), Option({ opt: options.menus.dashboard.powermenu.logout, title: 'Logout Command', type: 'string' }),
Option({ opt: options.menus.dashboard.powermenu.sleep, title: 'Sleep Command', type: 'string' }), Option({ opt: options.menus.dashboard.powermenu.sleep, title: 'Sleep Command', type: 'string' }),
Header('Controls'),
Option({ opt: options.menus.dashboard.controls.enabled, title: 'Enabled', type: 'boolean' }),
Header('Resource Usage Metrics'), Header('Resource Usage Metrics'),
Option({ opt: options.menus.dashboard.stats.enabled, title: 'Enabled', type: 'boolean' }),
Option({ Option({
opt: options.menus.dashboard.stats.enable_gpu, opt: options.menus.dashboard.stats.enable_gpu,
title: 'Track GPU', title: 'Track GPU',
subtitle: "NOTE: This is currently only available for NVidia GPUs and requires 'python-gpustat'.", subtitle: "NOTE: This is currently only available for NVidia GPUs and requires 'python-gpustat'.",
type: 'boolean', type: 'boolean',
}), }),
Header('Shortcuts'), Header('Shortcuts'),
Option({ opt: options.menus.dashboard.shortcuts.enabled, title: 'Enabled', type: 'boolean' }),
Option({ Option({
opt: options.menus.dashboard.shortcuts.left.shortcut1.icon, opt: options.menus.dashboard.shortcuts.left.shortcut1.icon,
title: 'Left - Shortcut 1 (Icon)', title: 'Left - Shortcut 1 (Icon)',

View File

@@ -45,6 +45,15 @@ export const NotificationSettings = (): Scrollable<Child, Attribute> => {
subtitle: 'The notification will follow the monitor of your cursor', subtitle: 'The notification will follow the monitor of your cursor',
type: 'boolean', type: 'boolean',
}), }),
Option({
opt: options.notifications.clearDelay,
title: 'Clear Delay',
subtitle:
'The delay in milliseconds before a notification is cleared' +
'\nWARNING: Setting this value too low may crash AGS depending on your system.',
type: 'number',
increment: 20,
}),
Option({ Option({
opt: options.notifications.timeout, opt: options.notifications.timeout,
title: 'Notification Timeout', title: 'Notification Timeout',

View File

@@ -40,6 +40,19 @@ export const NetworkMenuTheme = (): Scrollable<Child, Attribute> => {
type: 'color', type: 'color',
}), }),
Header('Switch'),
Option({
opt: options.theme.bar.menus.menu.network.switch.enabled,
title: 'Enabled',
type: 'color',
}),
Option({
opt: options.theme.bar.menus.menu.network.switch.disabled,
title: 'Disabled',
type: 'color',
}),
Option({ opt: options.theme.bar.menus.menu.network.switch.puck, title: 'Puck', type: 'color' }),
Header('List Items'), Header('List Items'),
Option({ Option({
opt: options.theme.bar.menus.menu.network.listitems.active, opt: options.theme.bar.menus.menu.network.listitems.active,

View File

@@ -1,11 +1,31 @@
import { Opt } from 'lib/option'; import { Opt } from 'lib/option';
import { Attribute, BoxWidget } from 'lib/types/widget'; import { Attribute, BoxWidget, Child } from 'lib/types/widget';
import FileChooserButton from 'types/widgets/filechooserbutton';
export const imageInputter = <T>(self: BoxWidget, opt: Opt<T>): Attribute => { export const imageInputter = <T>(self: BoxWidget, opt: Opt<T>): Attribute => {
return (self.child = Widget.FileChooserButton({ self.child = createFileChooserButton(opt);
class_name: 'image-chooser', return self.child;
on_file_set: ({ uri }) => { };
opt.value = uri!.replace('file://', '') as T;
}, const createFileChooserButton = <T>(opt: Opt<T>): FileChooserButton<Child, Attribute> => {
})); return Widget.FileChooserButton({
class_name: 'image-chooser',
on_file_set: handleFileSet(opt),
});
};
const handleFileSet =
<T>(opt: Opt<T>) =>
({ uri }: { uri: string | null }): void => {
if (!uri) {
console.warn('No URI selected');
return;
}
try {
const decodedPath = decodeURIComponent(uri.replace('file://', ''));
opt.value = decodedPath as T;
} catch (error) {
console.error('Failed to decode URI:', error);
}
}; };