many changed, added nixos-hardware
This commit is contained in:
parent
f4f1c5bba7
commit
2accd81424
149 changed files with 19124 additions and 238 deletions
207
modules/styling/config/widgets/sideright/calendar.js
Normal file
207
modules/styling/config/widgets/sideright/calendar.js
Normal file
|
@ -0,0 +1,207 @@
|
|||
const { Gio } = imports.gi;
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { Box, Button, Label } = Widget;
|
||||
import { MaterialIcon } from "../../lib/materialicon.js";
|
||||
import { getCalendarLayout } from "../../lib/calendarlayout.js";
|
||||
import { setupCursorHover } from "../../lib/cursorhover.js";
|
||||
|
||||
import { TodoWidget } from "./todolist.js";
|
||||
|
||||
let calendarJson = getCalendarLayout(undefined, true);
|
||||
let monthshift = 0;
|
||||
|
||||
function fileExists(filePath) {
|
||||
let file = Gio.File.new_for_path(filePath);
|
||||
return file.query_exists(null);
|
||||
}
|
||||
|
||||
function getDateInXMonthsTime(x) {
|
||||
var currentDate = new Date(); // Get the current date
|
||||
var targetMonth = currentDate.getMonth() + x; // Calculate the target month
|
||||
var targetYear = currentDate.getFullYear(); // Get the current year
|
||||
|
||||
// Adjust the year and month if necessary
|
||||
targetYear += Math.floor(targetMonth / 12);
|
||||
targetMonth = (targetMonth % 12 + 12) % 12;
|
||||
|
||||
// Create a new date object with the target year and month
|
||||
var targetDate = new Date(targetYear, targetMonth, 1);
|
||||
|
||||
// Set the day to the last day of the month to get the desired date
|
||||
// targetDate.setDate(0);
|
||||
|
||||
return targetDate;
|
||||
}
|
||||
|
||||
const weekDays = [ // MONDAY IS THE FIRST DAY OF THE WEEK :HESRIGHTYOUKNOW:
|
||||
{ day: 'Mo', today: 0 },
|
||||
{ day: 'Tu', today: 0 },
|
||||
{ day: 'We', today: 0 },
|
||||
{ day: 'Th', today: 0 },
|
||||
{ day: 'Fr', today: 0 },
|
||||
{ day: 'Sa', today: 0 },
|
||||
{ day: 'Su', today: 0 },
|
||||
]
|
||||
|
||||
const CalendarDay = (day, today) => Widget.Button({
|
||||
className: `sidebar-calendar-btn ${today == 1 ? 'sidebar-calendar-btn-today' : (today == -1 ? 'sidebar-calendar-btn-othermonth' : '')}`,
|
||||
child: Widget.Overlay({
|
||||
child: Box({}),
|
||||
overlays: [Label({
|
||||
hpack: 'center',
|
||||
className: 'txt-smallie txt-semibold sidebar-calendar-btn-txt',
|
||||
label: String(day),
|
||||
})],
|
||||
})
|
||||
})
|
||||
|
||||
const CalendarWidget = () => {
|
||||
const calendarMonthYear = Widget.Button({
|
||||
className: 'txt txt-large sidebar-calendar-monthyear-btn',
|
||||
onClicked: () => shiftCalendarXMonths(0),
|
||||
setup: (button) => {
|
||||
button.label = `${new Date().toLocaleString('default', { month: 'long' })} ${new Date().getFullYear()}`;
|
||||
setupCursorHover(button);
|
||||
}
|
||||
});
|
||||
const addCalendarChildren = (box, calendarJson) => {
|
||||
const children = box.get_children();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const child = children[i];
|
||||
child.destroy();
|
||||
}
|
||||
box.children = calendarJson.map((row, i) => Widget.Box({
|
||||
className: 'spacing-h-5',
|
||||
children: row.map((day, i) => CalendarDay(day.day, day.today)),
|
||||
}))
|
||||
}
|
||||
function shiftCalendarXMonths(x) {
|
||||
if (x == 0) monthshift = 0;
|
||||
else monthshift += x;
|
||||
var newDate;
|
||||
if (monthshift == 0) newDate = new Date();
|
||||
else newDate = getDateInXMonthsTime(monthshift);
|
||||
|
||||
calendarJson = getCalendarLayout(newDate, (monthshift == 0));
|
||||
calendarMonthYear.label = `${monthshift == 0 ? '' : '• '}${newDate.toLocaleString('default', { month: 'long' })} ${newDate.getFullYear()}`;
|
||||
addCalendarChildren(calendarDays, calendarJson);
|
||||
}
|
||||
const calendarHeader = Widget.Box({
|
||||
className: 'spacing-h-5 sidebar-calendar-header',
|
||||
setup: (box) => {
|
||||
box.pack_start(calendarMonthYear, false, false, 0);
|
||||
box.pack_end(Widget.Box({
|
||||
className: 'spacing-h-5',
|
||||
children: [
|
||||
Button({
|
||||
className: 'sidebar-calendar-monthshift-btn',
|
||||
onClicked: () => shiftCalendarXMonths(-1),
|
||||
child: MaterialIcon('chevron_left', 'norm'),
|
||||
setup: setupCursorHover,
|
||||
}),
|
||||
Button({
|
||||
className: 'sidebar-calendar-monthshift-btn',
|
||||
onClicked: () => shiftCalendarXMonths(1),
|
||||
child: MaterialIcon('chevron_right', 'norm'),
|
||||
setup: setupCursorHover,
|
||||
})
|
||||
]
|
||||
}), false, false, 0);
|
||||
}
|
||||
})
|
||||
const calendarDays = Widget.Box({
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
className: 'spacing-v-5',
|
||||
setup: (box) => {
|
||||
addCalendarChildren(box, calendarJson);
|
||||
}
|
||||
});
|
||||
return Widget.EventBox({
|
||||
onScrollUp: () => shiftCalendarXMonths(-1),
|
||||
onScrollDown: () => shiftCalendarXMonths(1),
|
||||
child: Widget.Box({
|
||||
hpack: 'center',
|
||||
children: [
|
||||
Widget.Box({
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
className: 'spacing-v-5',
|
||||
children: [
|
||||
calendarHeader,
|
||||
Widget.Box({
|
||||
homogeneous: true,
|
||||
className: 'spacing-h-5',
|
||||
children: weekDays.map((day, i) => CalendarDay(day.day, day.today))
|
||||
}),
|
||||
calendarDays,
|
||||
]
|
||||
})
|
||||
]
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
const defaultShown = 'calendar';
|
||||
const contentStack = Widget.Stack({
|
||||
hexpand: true,
|
||||
children: {
|
||||
'calendar': CalendarWidget(),
|
||||
'todo': TodoWidget(),
|
||||
// 'stars': Widget.Label({ label: 'GitHub feed will be here' }),
|
||||
},
|
||||
transition: 'slide_up_down',
|
||||
transitionDuration: 180,
|
||||
setup: (stack) => Utils.timeout(1, () => {
|
||||
stack.shown = defaultShown;
|
||||
})
|
||||
})
|
||||
|
||||
const StackButton = (stackItemName, icon, name) => Widget.Button({
|
||||
className: 'button-minsize sidebar-navrail-btn txt-small spacing-h-5',
|
||||
onClicked: (button) => {
|
||||
contentStack.shown = stackItemName;
|
||||
const kids = button.get_parent().get_children();
|
||||
for (let i = 0; i < kids.length; i++) {
|
||||
if (kids[i] != button) kids[i].toggleClassName('sidebar-navrail-btn-active', false);
|
||||
else button.toggleClassName('sidebar-navrail-btn-active', true);
|
||||
}
|
||||
},
|
||||
child: Box({
|
||||
className: 'spacing-v-5',
|
||||
vertical: true,
|
||||
children: [
|
||||
Label({
|
||||
className: `txt icon-material txt-hugeass`,
|
||||
label: icon,
|
||||
}),
|
||||
Label({
|
||||
label: name,
|
||||
className: 'txt txt-smallie',
|
||||
}),
|
||||
]
|
||||
}),
|
||||
setup: (button) => Utils.timeout(1, () => {
|
||||
setupCursorHover(button);
|
||||
button.toggleClassName('sidebar-navrail-btn-active', defaultShown === stackItemName);
|
||||
})
|
||||
});
|
||||
|
||||
export const ModuleCalendar = () => Box({
|
||||
className: 'sidebar-group spacing-h-5',
|
||||
setup: (box) => {
|
||||
box.pack_start(Box({
|
||||
vpack: 'center',
|
||||
homogeneous: true,
|
||||
vertical: true,
|
||||
className: 'sidebar-navrail spacing-v-10',
|
||||
children: [
|
||||
StackButton('calendar', 'calendar_month', 'Calendar'),
|
||||
StackButton('todo', 'lists', 'To Do'),
|
||||
// StackButton(box, 'stars', 'star', 'GitHub'),
|
||||
]
|
||||
}), false, false, 0);
|
||||
box.pack_end(contentStack, false, false, 0);
|
||||
}
|
||||
})
|
11
modules/styling/config/widgets/sideright/main.js
Normal file
11
modules/styling/config/widgets/sideright/main.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
import PopupWindow from '../../lib/popupwindow.js';
|
||||
import SidebarRight from "./sideright.js";
|
||||
|
||||
export default () => PopupWindow({
|
||||
keymode: 'exclusive',
|
||||
anchor: ['right', 'top', 'bottom'],
|
||||
name: 'sideright',
|
||||
showClassName: 'sideright-show',
|
||||
hideClassName: 'sideright-hide',
|
||||
child: SidebarRight(),
|
||||
});
|
142
modules/styling/config/widgets/sideright/notificationlist.js
Normal file
142
modules/styling/config/widgets/sideright/notificationlist.js
Normal file
|
@ -0,0 +1,142 @@
|
|||
// This file is for the notification list on the sidebar
|
||||
// For the popup notifications, see onscreendisplay.js
|
||||
// The actual widget for each single notification is in lib/notification.js
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||
const { Box, Button, Label, Scrollable, Stack } = Widget;
|
||||
import { MaterialIcon } from "../../lib/materialicon.js";
|
||||
import { setupCursorHover } from "../../lib/cursorhover.js";
|
||||
import Notification from "../../lib/notification.js";
|
||||
|
||||
export default (props) => {
|
||||
const notifEmptyContent = Box({
|
||||
homogeneous: true,
|
||||
children: [Box({
|
||||
vertical: true,
|
||||
vpack: 'center',
|
||||
className: 'txt spacing-v-10',
|
||||
children: [
|
||||
Box({
|
||||
vertical: true,
|
||||
className: 'spacing-v-5',
|
||||
children: [
|
||||
MaterialIcon('notifications_active', 'gigantic'),
|
||||
Label({ label: 'No notifications', className: 'txt-small' }),
|
||||
]
|
||||
}),
|
||||
]
|
||||
})]
|
||||
});
|
||||
const notificationList = Box({
|
||||
vertical: true,
|
||||
vpack: 'start',
|
||||
className: 'spacing-v-5-revealer',
|
||||
setup: (self) => self
|
||||
.hook(Notifications, (box, id) => {
|
||||
if (box.get_children().length == 0) { // On init there's no notif, or 1st notif
|
||||
Notifications.notifications
|
||||
.forEach(n => {
|
||||
box.pack_end(Notification({
|
||||
notifObject: n,
|
||||
isPopup: false,
|
||||
}), false, false, 0)
|
||||
});
|
||||
box.show_all();
|
||||
return;
|
||||
}
|
||||
// 2nd or later notif
|
||||
const notif = Notifications.getNotification(id);
|
||||
const NewNotif = Notification({
|
||||
notifObject: notif,
|
||||
isPopup: false,
|
||||
});
|
||||
if (NewNotif) {
|
||||
box.pack_end(NewNotif, false, false, 0);
|
||||
box.show_all();
|
||||
}
|
||||
}, 'notified')
|
||||
.hook(Notifications, (box, id) => {
|
||||
if (!id) return;
|
||||
for (const ch of box.children) {
|
||||
if (ch._id === id) {
|
||||
ch.attribute.destroyWithAnims();
|
||||
}
|
||||
}
|
||||
}, 'closed')
|
||||
,
|
||||
});
|
||||
const ListActionButton = (icon, name, action) => Button({
|
||||
className: 'notif-listaction-btn',
|
||||
onClicked: action,
|
||||
child: Box({
|
||||
className: 'spacing-h-5',
|
||||
children: [
|
||||
MaterialIcon(icon, 'norm'),
|
||||
Label({
|
||||
className: 'txt-small',
|
||||
label: name,
|
||||
})
|
||||
]
|
||||
}),
|
||||
setup: setupCursorHover,
|
||||
});
|
||||
const silenceButton = ListActionButton('notifications_paused', 'Silence', (self) => {
|
||||
Notifications.dnd = !Notifications.dnd;
|
||||
self.toggleClassName('notif-listaction-btn-enabled', Notifications.dnd);
|
||||
});
|
||||
const clearButton = ListActionButton('clear_all', 'Clear', () => {
|
||||
// Manual destruction is not necessary
|
||||
// since Notifications.clear() sends destroy signals to every notif
|
||||
Notifications.clear();
|
||||
});
|
||||
const listTitle = Box({
|
||||
vpack: 'start',
|
||||
className: 'sidebar-group-invisible txt spacing-h-5',
|
||||
children: [
|
||||
Label({
|
||||
hexpand: true,
|
||||
xalign: 0,
|
||||
className: 'txt-title-small margin-left-10',
|
||||
// ^ (extra margin on the left so that it looks similarly spaced
|
||||
// when compared to borderless "Clear" button on the right)
|
||||
label: 'Notifications',
|
||||
}),
|
||||
silenceButton,
|
||||
clearButton,
|
||||
]
|
||||
});
|
||||
const notifList = Scrollable({
|
||||
hexpand: true,
|
||||
hscroll: 'never',
|
||||
vscroll: 'automatic',
|
||||
child: Box({
|
||||
vexpand: true,
|
||||
// homogeneous: true,
|
||||
children: [notificationList],
|
||||
}),
|
||||
setup: (self) => {
|
||||
const vScrollbar = self.get_vscrollbar();
|
||||
vScrollbar.get_style_context().add_class('sidebar-scrollbar');
|
||||
}
|
||||
});
|
||||
const listContents = Stack({
|
||||
transition: 'crossfade',
|
||||
transitionDuration: 150,
|
||||
children: {
|
||||
'empty': notifEmptyContent,
|
||||
'list': notifList,
|
||||
},
|
||||
setup: (self) => self
|
||||
.hook(Notifications, (self) => self.shown = (Notifications.notifications.length > 0 ? 'list' : 'empty'))
|
||||
,
|
||||
});
|
||||
return Box({
|
||||
...props,
|
||||
className: 'sidebar-group spacing-v-5',
|
||||
vertical: true,
|
||||
children: [
|
||||
listTitle,
|
||||
listContents,
|
||||
]
|
||||
});
|
||||
}
|
226
modules/styling/config/widgets/sideright/quicktoggles.js
Normal file
226
modules/styling/config/widgets/sideright/quicktoggles.js
Normal file
|
@ -0,0 +1,226 @@
|
|||
const { GLib } = imports.gi;
|
||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
|
||||
import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js';
|
||||
import Network from 'resource:///com/github/Aylur/ags/service/network.js';
|
||||
const { execAsync, exec } = Utils;
|
||||
import { BluetoothIndicator, NetworkIndicator } from "../../lib/statusicons.js";
|
||||
import { setupCursorHover } from "../../lib/cursorhover.js";
|
||||
import { MaterialIcon } from '../../lib/materialicon.js';
|
||||
|
||||
function expandTilde(path) {
|
||||
if (path.startsWith('~')) {
|
||||
return GLib.get_home_dir() + path.slice(1);
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
export const ToggleIconWifi = (props = {}) => Widget.Button({
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: 'Wifi | Right-click to configure',
|
||||
onClicked: () => Network.toggleWifi(),
|
||||
onSecondaryClickRelease: () => {
|
||||
execAsync(['bash', '-c', 'XDG_CURRENT_DESKTOP="gnome" gnome-control-center wifi', '&']);
|
||||
App.closeWindow('sideright');
|
||||
},
|
||||
child: NetworkIndicator(),
|
||||
setup: (self) => {
|
||||
setupCursorHover(self);
|
||||
self.hook(Network, button => {
|
||||
button.toggleClassName('sidebar-button-active', [Network.wifi?.internet, Network.wired?.internet].includes('connected'))
|
||||
button.tooltipText = (`${Network.wifi?.ssid} | Right-click to configure` || 'Unknown');
|
||||
});
|
||||
},
|
||||
...props,
|
||||
});
|
||||
|
||||
export const ToggleIconBluetooth = (props = {}) => Widget.Button({
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: 'Bluetooth | Right-click to configure',
|
||||
onClicked: () => {
|
||||
const status = Bluetooth?.enabled;
|
||||
if (status)
|
||||
exec('rfkill block bluetooth');
|
||||
else
|
||||
exec('rfkill unblock bluetooth');
|
||||
},
|
||||
onSecondaryClickRelease: () => {
|
||||
execAsync(['bash', '-c', 'blueberry &']);
|
||||
App.closeWindow('sideright');
|
||||
},
|
||||
child: BluetoothIndicator(),
|
||||
setup: (self) => {
|
||||
setupCursorHover(self);
|
||||
self.hook(Bluetooth, button => {
|
||||
button.toggleClassName('sidebar-button-active', Bluetooth?.enabled)
|
||||
});
|
||||
},
|
||||
...props,
|
||||
});
|
||||
|
||||
export const HyprToggleIcon = async (icon, name, hyprlandConfigValue, props = {}) => {
|
||||
try {
|
||||
return Widget.Button({
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: `${name}`,
|
||||
onClicked: (button) => {
|
||||
// Set the value to 1 - value
|
||||
Utils.execAsync(`hyprctl -j getoption ${hyprlandConfigValue}`).then((result) => {
|
||||
const currentOption = JSON.parse(result).int;
|
||||
execAsync(['bash', '-c', `hyprctl keyword ${hyprlandConfigValue} ${1 - currentOption} &`]).catch(print);
|
||||
button.toggleClassName('sidebar-button-active', currentOption == 0);
|
||||
}).catch(print);
|
||||
},
|
||||
child: MaterialIcon(icon, 'norm', { hpack: 'center' }),
|
||||
setup: button => {
|
||||
button.toggleClassName('sidebar-button-active', JSON.parse(Utils.exec(`hyprctl -j getoption ${hyprlandConfigValue}`)).int == 1);
|
||||
setupCursorHover(button);
|
||||
},
|
||||
...props,
|
||||
})
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export const ModuleNightLight = (props = {}) => Widget.Button({ // TODO: Make this work
|
||||
attribute: {
|
||||
enabled: false,
|
||||
yellowlight: undefined,
|
||||
},
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: 'Night Light',
|
||||
onClicked: (self) => {
|
||||
self.attribute.enabled = !self.attribute.enabled;
|
||||
self.toggleClassName('sidebar-button-active', self.attribute.enabled);
|
||||
// if (self.attribute.enabled) Utils.execAsync(['bash', '-c', 'wlsunset & disown'])
|
||||
if (self.attribute.enabled) Utils.execAsync('wlsunset')
|
||||
else Utils.execAsync('pkill wlsunset');
|
||||
},
|
||||
child: MaterialIcon('nightlight', 'norm'),
|
||||
setup: (self) => {
|
||||
setupCursorHover(self);
|
||||
self.attribute.enabled = !!exec('pidof wlsunset');
|
||||
self.toggleClassName('sidebar-button-active', self.attribute.enabled);
|
||||
},
|
||||
...props,
|
||||
});
|
||||
|
||||
export const ModuleInvertColors = async (props = {}) => {
|
||||
try {
|
||||
const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
|
||||
return Widget.Button({
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: 'Color inversion',
|
||||
onClicked: (button) => {
|
||||
// const shaderPath = JSON.parse(exec('hyprctl -j getoption decoration:screen_shader')).str;
|
||||
Hyprland.sendMessage('j/getoption decoration:screen_shader')
|
||||
.then((output) => {
|
||||
const shaderPath = JSON.parse(output)["str"].trim();
|
||||
if (shaderPath != "[[EMPTY]]" && shaderPath != "") {
|
||||
execAsync(['bash', '-c', `hyprctl keyword decoration:screen_shader '[[EMPTY]]'`]).catch(print);
|
||||
button.toggleClassName('sidebar-button-active', false);
|
||||
}
|
||||
else {
|
||||
Hyprland.sendMessage(`j/keyword decoration:screen_shader ${expandTilde('~/.config/hypr/shaders/invert.frag')}`)
|
||||
.catch(print);
|
||||
button.toggleClassName('sidebar-button-active', true);
|
||||
}
|
||||
})
|
||||
},
|
||||
child: MaterialIcon('invert_colors', 'norm'),
|
||||
setup: setupCursorHover,
|
||||
...props,
|
||||
})
|
||||
} catch {
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
export const ModuleIdleInhibitor = (props = {}) => Widget.Button({ // TODO: Make this work
|
||||
attribute: {
|
||||
enabled: false,
|
||||
inhibitor: undefined,
|
||||
},
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: 'Keep system awake',
|
||||
onClicked: (self) => {
|
||||
self.attribute.enabled = !self.attribute.enabled;
|
||||
self.toggleClassName('sidebar-button-active', self.attribute.enabled);
|
||||
if (self.attribute.enabled) {
|
||||
self.attribute.inhibitor = Utils.subprocess(
|
||||
[`${App.configDir}/scripts/wayland-idle-inhibitor.py`],
|
||||
(output) => print(output),
|
||||
(err) => logError(err),
|
||||
self,
|
||||
);
|
||||
}
|
||||
else {
|
||||
self.attribute.inhibitor.force_exit();
|
||||
}
|
||||
},
|
||||
child: MaterialIcon('coffee', 'norm'),
|
||||
setup: setupCursorHover,
|
||||
...props,
|
||||
});
|
||||
|
||||
export const ModuleEditIcon = (props = {}) => Widget.Button({ // TODO: Make this work
|
||||
...props,
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
onClicked: () => {
|
||||
execAsync(['bash', '-c', 'XDG_CURRENT_DESKTOP="gnome" gnome-control-center', '&']);
|
||||
App.toggleWindow('sideright');
|
||||
},
|
||||
child: MaterialIcon('edit', 'norm'),
|
||||
setup: button => {
|
||||
setupCursorHover(button);
|
||||
}
|
||||
})
|
||||
|
||||
export const ModuleReloadIcon = (props = {}) => Widget.Button({
|
||||
...props,
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: 'Reload Environment config',
|
||||
onClicked: () => {
|
||||
execAsync(['bash', '-c', 'hyprctl reload || swaymsg reload &']);
|
||||
App.toggleWindow('sideright');
|
||||
},
|
||||
child: MaterialIcon('refresh', 'norm'),
|
||||
setup: button => {
|
||||
setupCursorHover(button);
|
||||
}
|
||||
})
|
||||
|
||||
export const ModuleSettingsIcon = (props = {}) => Widget.Button({
|
||||
...props,
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: 'Open Settings',
|
||||
onClicked: () => {
|
||||
execAsync(['bash', '-c', 'XDG_CURRENT_DESKTOP="gnome" gnome-control-center', '&']);
|
||||
App.toggleWindow('sideright');
|
||||
},
|
||||
child: MaterialIcon('settings', 'norm'),
|
||||
setup: button => {
|
||||
setupCursorHover(button);
|
||||
}
|
||||
})
|
||||
|
||||
export const ModulePowerIcon = (props = {}) => Widget.Button({
|
||||
...props,
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: 'Session',
|
||||
onClicked: () => {
|
||||
App.toggleWindow('session');
|
||||
App.closeWindow('sideright');
|
||||
},
|
||||
child: MaterialIcon('power_settings_new', 'norm'),
|
||||
setup: button => {
|
||||
setupCursorHover(button);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
86
modules/styling/config/widgets/sideright/sideright.js
Normal file
86
modules/styling/config/widgets/sideright/sideright.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { execAsync, exec } = Utils;
|
||||
const { Box, EventBox } = Widget;
|
||||
import {
|
||||
ToggleIconBluetooth,
|
||||
ToggleIconWifi,
|
||||
HyprToggleIcon,
|
||||
ModuleNightLight,
|
||||
ModuleInvertColors,
|
||||
ModuleIdleInhibitor,
|
||||
ModuleEditIcon,
|
||||
ModuleReloadIcon,
|
||||
ModuleSettingsIcon,
|
||||
ModulePowerIcon
|
||||
} from "./quicktoggles.js";
|
||||
import ModuleNotificationList from "./notificationlist.js";
|
||||
import { ModuleCalendar } from "./calendar.js";
|
||||
|
||||
const timeRow = Box({
|
||||
className: 'spacing-h-5 sidebar-group-invisible-morehorizpad',
|
||||
children: [
|
||||
Widget.Label({
|
||||
hpack: 'center',
|
||||
className: 'txt-small txt',
|
||||
setup: (self) => self
|
||||
.poll(5000, label => {
|
||||
execAsync(['bash', '-c', `w | sed -n '1p' | cut -d, -f1 | cut -d' ' -f4-`])
|
||||
.then(upTimeString => {
|
||||
label.label = `Uptime: ${upTimeString}`;
|
||||
}).catch(print);
|
||||
})
|
||||
,
|
||||
}),
|
||||
Widget.Box({ hexpand: true }),
|
||||
// ModuleEditIcon({ hpack: 'end' }), // TODO: Make this work
|
||||
ModuleReloadIcon({ hpack: 'end' }),
|
||||
ModuleSettingsIcon({ hpack: 'end' }),
|
||||
ModulePowerIcon({ hpack: 'end' }),
|
||||
]
|
||||
});
|
||||
|
||||
const togglesBox = Widget.Box({
|
||||
hpack: 'center',
|
||||
className: 'sidebar-togglesbox spacing-h-10',
|
||||
children: [
|
||||
ToggleIconWifi(),
|
||||
ToggleIconBluetooth(),
|
||||
await HyprToggleIcon('mouse', 'Raw input', 'input:force_no_accel', {}),
|
||||
await HyprToggleIcon('front_hand', 'No touchpad while typing', 'input:touchpad:disable_while_typing', {}),
|
||||
ModuleNightLight(),
|
||||
await ModuleInvertColors(),
|
||||
ModuleIdleInhibitor(),
|
||||
]
|
||||
})
|
||||
|
||||
export default () => Box({
|
||||
vexpand: true,
|
||||
hexpand: true,
|
||||
css: 'min-width: 2px;',
|
||||
children: [
|
||||
EventBox({
|
||||
onPrimaryClick: () => App.closeWindow('sideright'),
|
||||
onSecondaryClick: () => App.closeWindow('sideright'),
|
||||
onMiddleClick: () => App.closeWindow('sideright'),
|
||||
}),
|
||||
Box({
|
||||
vertical: true,
|
||||
vexpand: true,
|
||||
className: 'sidebar-right spacing-v-15',
|
||||
children: [
|
||||
Box({
|
||||
vertical: true,
|
||||
className: 'spacing-v-5',
|
||||
children: [
|
||||
timeRow,
|
||||
// togglesFlowBox,
|
||||
togglesBox,
|
||||
]
|
||||
}),
|
||||
ModuleNotificationList({ vexpand: true, }),
|
||||
ModuleCalendar(),
|
||||
]
|
||||
}),
|
||||
]
|
||||
});
|
279
modules/styling/config/widgets/sideright/todolist.js
Normal file
279
modules/styling/config/widgets/sideright/todolist.js
Normal file
|
@ -0,0 +1,279 @@
|
|||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { Box, Button, Label, Revealer } = Widget;
|
||||
import { MaterialIcon } from "../../lib/materialicon.js";
|
||||
import Todo from "../../services/todo.js";
|
||||
import { setupCursorHover } from "../../lib/cursorhover.js";
|
||||
import { NavigationIndicator } from "../../lib/navigationindicator.js";
|
||||
|
||||
const defaultTodoSelected = 'undone';
|
||||
|
||||
const todoListItem = (task, id, isDone, isEven = false) => {
|
||||
const crosser = Widget.Box({
|
||||
className: 'sidebar-todo-crosser',
|
||||
});
|
||||
const todoContent = Widget.Box({
|
||||
className: 'sidebar-todo-item spacing-h-5',
|
||||
children: [
|
||||
Widget.Label({
|
||||
hexpand: true,
|
||||
xalign: 0,
|
||||
wrap: true,
|
||||
className: 'txt txt-small sidebar-todo-txt',
|
||||
label: task.content,
|
||||
selectable: true,
|
||||
}),
|
||||
Widget.Button({ // Check/Uncheck
|
||||
vpack: 'center',
|
||||
className: 'txt sidebar-todo-item-action',
|
||||
child: MaterialIcon(`${isDone ? 'remove_done' : 'check'}`, 'norm', { vpack: 'center' }),
|
||||
onClicked: (self) => {
|
||||
const contentWidth = todoContent.get_allocated_width();
|
||||
crosser.toggleClassName('sidebar-todo-crosser-crossed', true);
|
||||
crosser.css = `margin-left: -${contentWidth}px;`;
|
||||
Utils.timeout(200, () => {
|
||||
widgetRevealer.revealChild = false;
|
||||
})
|
||||
Utils.timeout(350, () => {
|
||||
if (isDone)
|
||||
Todo.uncheck(id);
|
||||
else
|
||||
Todo.check(id);
|
||||
})
|
||||
},
|
||||
setup: setupCursorHover,
|
||||
}),
|
||||
Widget.Button({ // Remove
|
||||
vpack: 'center',
|
||||
className: 'txt sidebar-todo-item-action',
|
||||
child: MaterialIcon('delete_forever', 'norm', { vpack: 'center' }),
|
||||
onClicked: () => {
|
||||
const contentWidth = todoContent.get_allocated_width();
|
||||
crosser.toggleClassName('sidebar-todo-crosser-removed', true);
|
||||
crosser.css = `margin-left: -${contentWidth}px;`;
|
||||
Utils.timeout(200, () => {
|
||||
widgetRevealer.revealChild = false;
|
||||
})
|
||||
Utils.timeout(350, () => {
|
||||
Todo.remove(id);
|
||||
})
|
||||
},
|
||||
setup: setupCursorHover,
|
||||
}),
|
||||
crosser,
|
||||
]
|
||||
});
|
||||
const widgetRevealer = Widget.Revealer({
|
||||
revealChild: true,
|
||||
transition: 'slide_down',
|
||||
transitionDuration: 150,
|
||||
child: todoContent,
|
||||
})
|
||||
return widgetRevealer;
|
||||
}
|
||||
|
||||
const todoItems = (isDone) => Widget.Scrollable({
|
||||
hscroll: 'never',
|
||||
vscroll: 'automatic',
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
setup: (self) => self
|
||||
.hook(Todo, (self) => {
|
||||
self.children = Todo.todo_json.map((task, i) => {
|
||||
if (task.done != isDone) return null;
|
||||
return todoListItem(task, i, isDone);
|
||||
})
|
||||
if (self.children.length == 0) {
|
||||
self.homogeneous = true;
|
||||
self.children = [
|
||||
Widget.Box({
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
vpack: 'center',
|
||||
className: 'txt',
|
||||
children: [
|
||||
MaterialIcon(`${isDone ? 'checklist' : 'check_circle'}`, 'gigantic'),
|
||||
Label({ label: `${isDone ? 'Finished tasks will go here' : 'Nothing here!'}` })
|
||||
]
|
||||
})
|
||||
]
|
||||
}
|
||||
else self.homogeneous = false;
|
||||
}, 'updated')
|
||||
,
|
||||
}),
|
||||
setup: (listContents) => {
|
||||
const vScrollbar = listContents.get_vscrollbar();
|
||||
vScrollbar.get_style_context().add_class('sidebar-scrollbar');
|
||||
}
|
||||
});
|
||||
|
||||
const UndoneTodoList = () => {
|
||||
const newTaskButton = Revealer({
|
||||
transition: 'slide_left',
|
||||
transitionDuration: 200,
|
||||
revealChild: true,
|
||||
child: Button({
|
||||
className: 'txt-small sidebar-todo-new',
|
||||
halign: 'end',
|
||||
vpack: 'center',
|
||||
label: '+ New task',
|
||||
setup: setupCursorHover,
|
||||
onClicked: (self) => {
|
||||
newTaskButton.revealChild = false;
|
||||
newTaskEntryRevealer.revealChild = true;
|
||||
confirmAddTask.revealChild = true;
|
||||
cancelAddTask.revealChild = true;
|
||||
newTaskEntry.grab_focus();
|
||||
}
|
||||
})
|
||||
});
|
||||
const cancelAddTask = Revealer({
|
||||
transition: 'slide_right',
|
||||
transitionDuration: 200,
|
||||
revealChild: false,
|
||||
child: Button({
|
||||
className: 'txt-norm icon-material sidebar-todo-add',
|
||||
halign: 'end',
|
||||
vpack: 'center',
|
||||
label: 'close',
|
||||
setup: setupCursorHover,
|
||||
onClicked: (self) => {
|
||||
newTaskEntryRevealer.revealChild = false;
|
||||
confirmAddTask.revealChild = false;
|
||||
cancelAddTask.revealChild = false;
|
||||
newTaskButton.revealChild = true;
|
||||
newTaskEntry.text = '';
|
||||
}
|
||||
})
|
||||
});
|
||||
const newTaskEntry = Widget.Entry({
|
||||
// hexpand: true,
|
||||
vpack: 'center',
|
||||
className: 'txt-small sidebar-todo-entry',
|
||||
placeholderText: 'Add a task...',
|
||||
onAccept: ({ text }) => {
|
||||
if (text == '') return;
|
||||
Todo.add(text)
|
||||
newTaskEntry.text = '';
|
||||
},
|
||||
onChange: ({ text }) => confirmAddTask.child.toggleClassName('sidebar-todo-add-available', text != ''),
|
||||
});
|
||||
const newTaskEntryRevealer = Revealer({
|
||||
transition: 'slide_right',
|
||||
transitionDuration: 200,
|
||||
revealChild: false,
|
||||
child: newTaskEntry,
|
||||
});
|
||||
const confirmAddTask = Revealer({
|
||||
transition: 'slide_right',
|
||||
transitionDuration: 200,
|
||||
revealChild: false,
|
||||
child: Button({
|
||||
className: 'txt-norm icon-material sidebar-todo-add',
|
||||
halign: 'end',
|
||||
vpack: 'center',
|
||||
label: 'arrow_upward',
|
||||
setup: setupCursorHover,
|
||||
onClicked: (self) => {
|
||||
if (newTaskEntry.text == '') return;
|
||||
Todo.add(newTaskEntry.text);
|
||||
newTaskEntry.text = '';
|
||||
}
|
||||
})
|
||||
});
|
||||
return Box({ // The list, with a New button
|
||||
vertical: true,
|
||||
className: 'spacing-v-5',
|
||||
setup: (box) => {
|
||||
box.pack_start(todoItems(false), true, true, 0);
|
||||
box.pack_start(Box({
|
||||
setup: (self) => {
|
||||
self.pack_start(cancelAddTask, false, false, 0);
|
||||
self.pack_start(newTaskEntryRevealer, true, true, 0);
|
||||
self.pack_start(confirmAddTask, false, false, 0);
|
||||
self.pack_start(newTaskButton, false, false, 0);
|
||||
}
|
||||
}), false, false, 0);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const todoItemsBox = Widget.Stack({
|
||||
vpack: 'fill',
|
||||
transition: 'slide_left_right',
|
||||
children: {
|
||||
'undone': UndoneTodoList(),
|
||||
'done': todoItems(true),
|
||||
},
|
||||
});
|
||||
|
||||
export const TodoWidget = () => {
|
||||
const TodoTabButton = (isDone, navIndex) => Widget.Button({
|
||||
hexpand: true,
|
||||
className: 'sidebar-selector-tab',
|
||||
onClicked: (button) => {
|
||||
todoItemsBox.shown = `${isDone ? 'done' : 'undone'}`;
|
||||
const kids = button.get_parent().get_children();
|
||||
for (let i = 0; i < kids.length; i++) {
|
||||
if (kids[i] != button) kids[i].toggleClassName('sidebar-selector-tab-active', false);
|
||||
else button.toggleClassName('sidebar-selector-tab-active', true);
|
||||
}
|
||||
// Fancy highlighter line width
|
||||
const buttonWidth = button.get_allocated_width();
|
||||
const highlightWidth = button.get_children()[0].get_allocated_width();
|
||||
navIndicator.css = `
|
||||
font-size: ${navIndex}px;
|
||||
padding: 0px ${(buttonWidth - highlightWidth) / 2}px;
|
||||
`;
|
||||
},
|
||||
child: Box({
|
||||
hpack: 'center',
|
||||
className: 'spacing-h-5',
|
||||
children: [
|
||||
MaterialIcon(`${isDone ? 'task_alt' : 'format_list_bulleted'}`, 'larger'),
|
||||
Label({
|
||||
className: 'txt txt-smallie',
|
||||
label: `${isDone ? 'Done' : 'Unfinished'}`,
|
||||
})
|
||||
]
|
||||
}),
|
||||
setup: (button) => Utils.timeout(1, () => {
|
||||
setupCursorHover(button);
|
||||
button.toggleClassName('sidebar-selector-tab-active', defaultTodoSelected === `${isDone ? 'done' : 'undone'}`);
|
||||
}),
|
||||
});
|
||||
const undoneButton = TodoTabButton(false, 0);
|
||||
const doneButton = TodoTabButton(true, 1);
|
||||
const navIndicator = NavigationIndicator(2, false, { // The line thing
|
||||
className: 'sidebar-selector-highlight',
|
||||
css: 'font-size: 0px; padding: 0rem 1.636rem;', // Shush
|
||||
})
|
||||
return Widget.Box({
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
className: 'spacing-v-10',
|
||||
setup: (box) => { // undone/done selector rail
|
||||
box.pack_start(Widget.Box({
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
className: 'sidebar-selectors spacing-h-5',
|
||||
homogeneous: true,
|
||||
setup: (box) => {
|
||||
box.pack_start(undoneButton, false, true, 0);
|
||||
box.pack_start(doneButton, false, true, 0);
|
||||
}
|
||||
}),
|
||||
Widget.Box({
|
||||
className: 'sidebar-selector-highlight-offset',
|
||||
homogeneous: true,
|
||||
children: [navIndicator]
|
||||
})
|
||||
]
|
||||
}), false, false, 0);
|
||||
box.pack_end(todoItemsBox, true, true, 0);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue