many changed, added nixos-hardware

This commit is contained in:
Vali 2024-07-07 13:23:38 +02:00
commit b699fff171
149 changed files with 19124 additions and 238 deletions

View file

@ -0,0 +1,199 @@
// It's weird, I know
const { Gio, GLib } = imports.gi;
import Service from 'resource:///com/github/Aylur/ags/service.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
const { exec, execAsync } = Utils;
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
export class ColorPickerSelection extends Service {
static {
Service.register(this, {
'picked': [],
'assigned': ['int'],
'hue': [],
'sl': [],
});
}
_hue = 198;
_xAxis = 94;
_yAxis = 80;
get hue() { return this._hue; }
set hue(value) {
this._hue = clamp(value, 0, 360);
this.emit('hue');
this.emit('picked');
this.emit('changed');
}
get xAxis() { return this._xAxis; }
set xAxis(value) {
this._xAxis = clamp(value, 0, 100);
this.emit('sl');
this.emit('picked');
this.emit('changed');
}
get yAxis() { return this._yAxis; }
set yAxis(value) {
this._yAxis = clamp(value, 0, 100);
this.emit('sl');
this.emit('picked');
this.emit('changed');
}
setColorFromHex(hexString, id) {
const hsl = hexToHSL(hexString);
this._hue = hsl.hue;
this._xAxis = hsl.saturation;
// this._yAxis = hsl.lightness;
this._yAxis = (100 - hsl.saturation / 2) / 100 * hsl.lightness;
// console.log(this._hue, this._xAxis, this._yAxis)
this.emit('assigned', id);
this.emit('changed');
}
constructor() {
super();
this.emit('changed');
}
}
export function hslToRgbValues(h, s, l) {
h /= 360;
s /= 100;
l /= 100;
let r, g, b;
if (s === 0) {
r = g = b = l; // achromatic
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
const to255 = x => Math.round(x * 255);
r = to255(r);
g = to255(g);
b = to255(b);
return `${Math.round(r)},${Math.round(g)},${Math.round(b)}`;
// return `rgb(${r},${g},${b})`;
}
export function hslToHex(h, s, l) {
h /= 360;
s /= 100;
l /= 100;
let r, g, b;
if (s === 0) {
r = g = b = l; // achromatic
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
const toHex = x => {
const hex = Math.round(x * 255).toString(16);
return hex.length === 1 ? "0" + hex : hex;
};
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
// export function hexToHSL(hex) {
// // Remove the '#' if present
// hex = hex.replace(/^#/, '');
// // Parse the hex value into RGB components
// const bigint = parseInt(hex, 16);
// const r = (bigint >> 16) & 255;
// const g = (bigint >> 8) & 255;
// const b = bigint & 255;
// // Normalize RGB values to range [0, 1]
// const normalizedR = r / 255;
// const normalizedG = g / 255;
// const normalizedB = b / 255;
// // Find the maximum and minimum values
// const max = Math.max(normalizedR, normalizedG, normalizedB);
// const min = Math.min(normalizedR, normalizedG, normalizedB);
// // Calculate the lightness
// const lightness = (max + min) / 2;
// // If the color is grayscale, set saturation to 0
// if (max === min) {
// return {
// hue: 0,
// saturation: 0,
// lightness: lightness * 100 // Convert to percentage
// };
// }
// // Calculate the saturation
// const d = max - min;
// const saturation = lightness > 0.5 ? d / (2 - max - min) : d / (max + min);
// // Calculate the hue
// let hue;
// if (max === normalizedR) {
// hue = ((normalizedG - normalizedB) / d + (normalizedG < normalizedB ? 6 : 0)) * 60;
// } else if (max === normalizedG) {
// hue = ((normalizedB - normalizedR) / d + 2) * 60;
// } else {
// hue = ((normalizedR - normalizedG) / d + 4) * 60;
// }
// return {
// hue: Math.round(hue),
// saturation: Math.round(saturation * 100), // Convert to percentage
// lightness: Math.round(lightness * 100) // Convert to percentage
// };
// }
export function hexToHSL(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
var r = parseInt(result[1], 16);
var g = parseInt(result[2], 16);
var b = parseInt(result[3], 16);
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0; // achromatic
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
s = s * 100;
s = Math.round(s);
l = l * 100;
l = Math.round(l);
h = Math.round(360 * h);
return {
hue: h,
saturation: s,
lightness: l
};
}

View file

@ -0,0 +1,284 @@
// TODO: Make selection update when entry changes
const { Gtk } = imports.gi;
import App from 'resource:///com/github/Aylur/ags/app.js';
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
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, Button, Entry, EventBox, Icon, Label, Overlay, Scrollable } = Widget;
import SidebarModule from './module.js';
import { MaterialIcon } from '../../../lib/materialicon.js';
import { setupCursorHover } from '../../../lib/cursorhover.js';
import { ColorPickerSelection, hslToHex, hslToRgbValues, hexToHSL } from './color.js';
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
export default () => {
const selectedColor = new ColorPickerSelection();
function shouldUseBlackColor() {
return ((selectedColor.xAxis < 40 || (45 <= selectedColor.hue && selectedColor.hue <= 195)) &&
selectedColor.yAxis > 60);
}
const colorBlack = 'rgba(0,0,0,0.9)';
const colorWhite = 'rgba(255,255,255,0.9)';
const hueRange = Box({
homogeneous: true,
className: 'sidebar-module-colorpicker-wrapper',
children: [Box({
className: 'sidebar-module-colorpicker-hue',
css: `background: linear-gradient(to bottom, #ff6666, #ffff66, #66dd66, #66ffff, #6666ff, #ff66ff, #ff6666);`,
})],
});
const hueSlider = Box({
vpack: 'start',
className: 'sidebar-module-colorpicker-cursorwrapper',
css: `margin-top: ${13.636 * selectedColor.hue / 360}rem;`,
homogeneous: true,
children: [Box({
className: 'sidebar-module-colorpicker-hue-cursor',
})],
setup: (self) => self.hook(selectedColor, () => {
const widgetHeight = hueRange.children[0].get_allocated_height();
self.setCss(`margin-top: ${13.636 * selectedColor.hue / 360}rem;`)
}),
});
const hueSelector = Box({
children: [EventBox({
child: Overlay({
child: hueRange,
overlays: [hueSlider],
}),
attribute: {
clicked: false,
setHue: (self, event) => {
const widgetHeight = hueRange.children[0].get_allocated_height();
const [_, cursorX, cursorY] = event.get_coords();
const cursorYPercent = clamp(cursorY / widgetHeight, 0, 1);
selectedColor.hue = Math.round(cursorYPercent * 360);
}
},
setup: (self) => self
.on('motion-notify-event', (self, event) => {
if (!self.attribute.clicked) return;
self.attribute.setHue(self, event);
})
.on('button-press-event', (self, event) => {
if (!(event.get_button()[1] === 1)) return; // We're only interested in left-click here
self.attribute.clicked = true;
self.attribute.setHue(self, event);
})
.on('button-release-event', (self) => self.attribute.clicked = false)
,
})]
});
const saturationAndLightnessRange = Box({
homogeneous: true,
children: [Box({
className: 'sidebar-module-colorpicker-saturationandlightness',
attribute: {
update: (self) => {
// css: `background: linear-gradient(to right, #ffffff, color);`,
self.setCss(`background:
linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,1)),
linear-gradient(to right, #ffffff, ${hslToHex(selectedColor.hue, 100, 50)});
`);
},
},
setup: (self) => self
.hook(selectedColor, self.attribute.update, 'hue')
.hook(selectedColor, self.attribute.update, 'assigned')
,
})],
});
const saturationAndLightnessCursor = Box({
className: 'sidebar-module-colorpicker-saturationandlightness-cursorwrapper',
children: [Box({
vpack: 'start',
hpack: 'start',
homogeneous: true,
css: `
margin-left: ${13.636 * selectedColor.xAxis / 100}rem;
margin-top: ${13.636 * (100 - selectedColor.yAxis) / 100}rem;
`, // Why 13.636rem? see class name in stylesheet
attribute: {
update: (self) => {
const allocation = saturationAndLightnessRange.children[0].get_allocation();
self.setCss(`
margin-left: ${13.636 * selectedColor.xAxis / 100}rem;
margin-top: ${13.636 * (100 - selectedColor.yAxis) / 100}rem;
`); // Why 13.636rem? see class name in stylesheet
}
},
setup: (self) => self
.hook(selectedColor, self.attribute.update, 'sl')
.hook(selectedColor, self.attribute.update, 'assigned')
,
children: [Box({
className: 'sidebar-module-colorpicker-saturationandlightness-cursor',
css: `
background-color: ${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))};
border-color: ${shouldUseBlackColor() ? colorBlack : colorWhite};
`,
attribute: {
update: (self) => {
self.setCss(`
background-color: ${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))};
border-color: ${shouldUseBlackColor() ? colorBlack : colorWhite};
`);
}
},
setup: (self) => self
.hook(selectedColor, self.attribute.update, 'sl')
.hook(selectedColor, self.attribute.update, 'hue')
.hook(selectedColor, self.attribute.update, 'assigned')
,
})],
})]
});
const saturationAndLightnessSelector = Box({
homogeneous: true,
className: 'sidebar-module-colorpicker-saturationandlightness-wrapper',
children: [EventBox({
child: Overlay({
child: saturationAndLightnessRange,
overlays: [saturationAndLightnessCursor],
}),
attribute: {
clicked: false,
setSaturationAndLightness: (self, event) => {
const allocation = saturationAndLightnessRange.children[0].get_allocation();
const [_, cursorX, cursorY] = event.get_coords();
const cursorXPercent = clamp(cursorX / allocation.width, 0, 1);
const cursorYPercent = clamp(cursorY / allocation.height, 0, 1);
selectedColor.xAxis = Math.round(cursorXPercent * 100);
selectedColor.yAxis = Math.round(100 - cursorYPercent * 100);
}
},
setup: (self) => self
.on('motion-notify-event', (self, event) => {
if (!self.attribute.clicked) return;
self.attribute.setSaturationAndLightness(self, event);
})
.on('button-press-event', (self, event) => {
if (!(event.get_button()[1] === 1)) return; // We're only interested in left-click here
self.attribute.clicked = true;
self.attribute.setSaturationAndLightness(self, event);
})
.on('button-release-event', (self) => self.attribute.clicked = false)
,
})]
});
const resultColorBox = Box({
className: 'sidebar-module-colorpicker-result-box',
homogeneous: true,
css: `background-color: ${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))};`,
children: [Label({
className: 'txt txt-small',
label: 'Result',
}),],
attribute: {
update: (self) => {
self.setCss(`background-color: ${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))};`);
self.children[0].setCss(`color: ${shouldUseBlackColor() ? colorBlack : colorWhite};`)
}
},
setup: (self) => self
.hook(selectedColor, self.attribute.update, 'sl')
.hook(selectedColor, self.attribute.update, 'hue')
.hook(selectedColor, self.attribute.update, 'assigned')
,
});
const ResultBox = ({ colorSystemName, updateCallback, copyCallback }) => Box({
children: [
Box({
vertical: true,
hexpand: true,
children: [
Label({
xalign: 0,
className: 'txt-tiny',
label: colorSystemName,
}),
Overlay({
child: Entry({
widthChars: 10,
className: 'txt-small techfont',
attribute: {
id: 0,
update: updateCallback,
},
setup: (self) => self
.hook(selectedColor, self.attribute.update, 'sl')
.hook(selectedColor, self.attribute.update, 'hue')
.hook(selectedColor, self.attribute.update, 'assigned')
// .on('activate', (self) => {
// const newColor = self.text;
// if (newColor.length != 7) return;
// selectedColor.setColorFromHex(self.text, self.attribute.id);
// })
,
}),
})
]
}),
Button({
child: MaterialIcon('content_copy', 'norm'),
onClicked: (self) => {
copyCallback(self);
self.child.label = 'done';
Utils.timeout(1000, () => self.child.label = 'content_copy');
},
setup: setupCursorHover,
})
]
});
const resultHex = ResultBox({
colorSystemName: 'Hex',
updateCallback: (self, id) => {
if (id && self.attribute.id === id) return;
self.text = hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100));
},
copyCallback: () => Utils.execAsync(['wl-copy', `${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))}`]),
})
const resultRgb = ResultBox({
colorSystemName: 'RGB',
updateCallback: (self, id) => {
if (id && self.attribute.id === id) return;
self.text = hslToRgbValues(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100));
},
copyCallback: () => Utils.execAsync(['wl-copy', `rgb(${hslToRgbValues(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))})`]),
})
const resultHsl = ResultBox({
colorSystemName: 'HSL',
updateCallback: (self, id) => {
if (id && self.attribute.id === id) return;
self.text = `${selectedColor.hue},${selectedColor.xAxis}%,${Math.round(selectedColor.yAxis / (1 + selectedColor.xAxis / 100))}%`;
},
copyCallback: () => Utils.execAsync(['wl-copy', `hsl(${selectedColor.hue},${selectedColor.xAxis}%,${Math.round(selectedColor.yAxis / (1 + selectedColor.xAxis / 100))}%)`]),
})
const result = Box({
className: 'sidebar-module-colorpicker-result-area spacing-v-5 txt',
hexpand: true,
vertical: true,
children: [
resultColorBox,
resultHex,
resultRgb,
resultHsl,
]
})
return SidebarModule({
icon: MaterialIcon('colorize', 'norm'),
name: 'Color picker',
revealChild: false,
child: Box({
className: 'spacing-h-5',
children: [
hueSelector,
saturationAndLightnessSelector,
result,
]
})
});
}

View file

@ -0,0 +1,56 @@
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
import { setupCursorHover } from '../../../lib/cursorhover.js';
import { MaterialIcon } from '../../../lib/materialicon.js';
const { Box, Button, Icon, Label, Revealer } = Widget;
export default ({
icon,
name,
child,
revealChild = true,
}) => {
const headerButtonIcon = MaterialIcon(revealChild ? 'expand_less' : 'expand_more', 'norm');
const header = Button({
onClicked: () => {
content.revealChild = !content.revealChild;
headerButtonIcon.label = content.revealChild ? 'expand_less' : 'expand_more';
},
setup: setupCursorHover,
child: Box({
className: 'txt spacing-h-10',
children: [
icon,
Label({
className: 'txt-norm',
label: `${name}`,
}),
Box({
hexpand: true,
}),
Box({
className: 'sidebar-module-btn-arrow',
homogeneous: true,
children: [headerButtonIcon],
})
]
})
});
const content = Revealer({
revealChild: revealChild,
transition: 'slide_down',
transitionDuration: 200,
child: Box({
className: 'margin-top-5',
homogeneous: true,
children: [child],
}),
});
return Box({
className: 'sidebar-module',
vertical: true,
children: [
header,
content,
]
});
}

View file

@ -0,0 +1,95 @@
const { Gtk } = 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';
const { execAsync, exec } = Utils;
const { Box, Button, EventBox, Icon, Label, Scrollable } = Widget;
import SidebarModule from './module.js';
import { MaterialIcon } from '../../../lib/materialicon.js';
import { setupCursorHover } from '../../../lib/cursorhover.js';
Gtk.IconTheme.get_default().append_search_path(`${App.configDir}/assets`);
const distroID = exec(`bash -c 'cat /etc/os-release | grep "^ID=" | cut -d "=" -f 2'`).trim();
const isDebianDistro = (distroID == 'linuxmint' || distroID == 'ubuntu' || distroID == 'debian' || distroID == 'zorin' || distroID == 'pop' || distroID == 'raspbian' || distroID == 'kali' || distroID == 'elementary');
const isArchDistro = (distroID == 'arch' || distroID == 'endeavouros');
const hasFlatpak = !!exec(`bash -c 'command -v flatpak'`);
const scripts = [
{
icon: 'nixos-symbolic',
name: 'Trim system generations to 5',
command: `sudo ${App.configDir}/scripts/quickscripts/nixos-trim-generations.sh 5 0 system`,
enabled: distroID == 'nixos',
},
{
icon: 'nixos-symbolic',
name: 'Trim home manager generations to 5',
command: `${App.configDir}/scripts/quickscripts/nixos-trim-generations.sh 5 0 home-manager`,
enabled: distroID == 'nixos',
},
{
icon: 'ubuntu-symbolic',
name: 'Update packages',
command: `sudo apt update && sudo apt upgrade -y`,
enabled: isDebianDistro,
},
{
icon: 'fedora-symbolic',
name: 'Update packages',
command: `sudo dnf upgrade -y`,
enabled: distroID == 'fedora',
},
{
icon: 'arch-symbolic',
name: 'Update packages',
command: `sudo pacman -Syyu`,
enabled: isArchDistro,
},
{
icon: 'flatpak-symbolic',
name: 'Uninstall unused flatpak packages',
command: `flatpak uninstall --unused`,
enabled: hasFlatpak,
},
];
export default () => SidebarModule({
icon: MaterialIcon('code', 'norm'),
name: 'Quick scripts',
child: Box({
vertical: true,
className: 'spacing-v-5',
children: scripts.map((script) => {
if (!script.enabled) return null;
const scriptStateIcon = MaterialIcon('not_started', 'norm');
return Box({
className: 'spacing-h-5 txt',
children: [
Icon({
className: 'sidebar-module-btn-icon txt-large',
icon: script.icon,
}),
Label({
className: 'txt-small',
hpack: 'start',
hexpand: true,
label: script.name,
tooltipText: script.command,
}),
Button({
className: 'sidebar-module-scripts-button',
child: scriptStateIcon,
onClicked: () => {
App.closeWindow('sideleft');
execAsync([`bash`, `-c`, `foot fish -C "${script.command}"`]).catch(print)
.then(() => {
scriptStateIcon.label = 'done';
})
},
setup: setupCursorHover,
}),
],
})
}),
})
});