Merge branch 'ryo' into ryo

This commit is contained in:
Mephisto
2025-06-16 15:55:39 +03:00
committed by GitHub
27 changed files with 192 additions and 115 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
import { ResultWidget, ResultWidgetProps } from "../../widget/runner/ResultWidget"; import { ResultWidget, ResultWidgetProps } from "../../widget/runner/ResultWidget";
import AstalApps from "gi://AstalApps"; import AstalApps from "gi://AstalApps";
import { cleanExec, getAstalApps, updateApps } from "../../scripts/apps"; import { execApp, getAstalApps, updateApps } from "../../scripts/apps";
import { Runner } from "../Runner"; import { Runner } from "../Runner";
import { Astal } from "astal/gtk3"; import { Astal } from "astal/gtk3";
@@ -15,7 +15,7 @@ export const PluginApps = {
title: app.get_name(), title: app.get_name(),
description: app.get_description(), description: app.get_description(),
icon: Astal.Icon.lookup_icon(app.iconName) ? app.iconName : "application-x-executable-symbolic", icon: Astal.Icon.lookup_icon(app.iconName) ? app.iconName : "application-x-executable-symbolic",
onClick: () => cleanExec(app) onClick: () => execApp(app)
} as ResultWidgetProps) } as ResultWidgetProps)
); );
} }
+3 -3
View File
@@ -12,12 +12,12 @@ export const PluginClipboard = {
if(Clipboard.getDefault().history.length < 1) if(Clipboard.getDefault().history.length < 1)
return new ResultWidget({ return new ResultWidget({
icon: "edit-paste-symbolic", icon: "edit-paste-symbolic",
title: "No clipboard items found!", title: "Clipboard is empty",
description: "When something is copied, it'll be shown right here!" description: "Copy something and it will be shown right here!"
} as ResultWidgetProps); } as ResultWidgetProps);
return Clipboard.getDefault().history.filter(item => // not the best way to search, but it works return Clipboard.getDefault().history.filter(item => // not the best way to search, but it works
Runner.regExMatch(search, item.id.toString()) || Runner.regExMatch(search, item.preview)).map((item) => Runner.regExMatch(search, item.id) || Runner.regExMatch(search, item.preview)).map((item) =>
new ResultWidget({ new ResultWidget({
icon: new Widget.Label({ icon: new Widget.Label({
label: item.id.toString(), label: item.id.toString(),
+12 -2
View File
@@ -2,8 +2,12 @@ import { Astal } from "astal/gtk3";
import AstalApps from "gi://AstalApps"; import AstalApps from "gi://AstalApps";
import AstalHyprland from "gi://AstalHyprland"; import AstalHyprland from "gi://AstalHyprland";
import { execAsync } from "astal";
const astalApps: AstalApps.Apps = new AstalApps.Apps(); const astalApps: AstalApps.Apps = new AstalApps.Apps();
const uwsmIsActive: boolean = await execAsync("uwsm check is-active").then((stdout) =>
/hyprland/gi.test(stdout)).catch(() => false);
let appsList: Array<AstalApps.Application> = astalApps.get_list(); let appsList: Array<AstalApps.Application> = astalApps.get_list();
export function getApps(): Array<AstalApps.Application> { export function getApps(): Array<AstalApps.Application> {
@@ -19,8 +23,14 @@ export function getAstalApps(): AstalApps.Apps {
return astalApps; return astalApps;
} }
export function cleanExec(app: AstalApps.Application): void { /** handles running with uwsm if it's installed */
AstalHyprland.get_default().dispatch("exec", app.executable.replace(/(%f|%F|%u|%U|%i|%c|%k)/g, "")); export function execApp(app: AstalApps.Application|string, dispatchExecArgs?: string) {
const executable = (typeof app === "string") ? app
: app.executable.replace(/(%f|%F|%u|%U|%i|%c|%k)/g, "");
AstalHyprland.get_default().dispatch("exec",
`${dispatchExecArgs ? `${dispatchExecArgs} ` : ""}${uwsmIsActive ? "uwsm app -- " : ""}${executable}`
);
} }
export function getAppsByName(appName: string): (Array<AstalApps.Application>|undefined) { export function getAppsByName(appName: string): (Array<AstalApps.Application>|undefined) {
+10 -11
View File
@@ -22,11 +22,10 @@ class NightLight extends GObject.Object {
public get gamma() { return this.#gamma; } public get gamma() { return this.#gamma; }
public set gamma(newValue: number) { this.setGamma(newValue); } public set gamma(newValue: number) { this.setGamma(newValue); }
@property(Number) public readonly maxTemperature = 20000;
public get maxTemperature() { return 20000; } public readonly minTemperature = 1000;
public readonly identityTemperature = 6000;
@property(Number) public readonly maxGamma = 100;
public get maxGamma() { return 100; }
@property(Boolean) @property(Boolean)
public get identity() { return this.#identity; } public get identity() { return this.#identity; }
@@ -72,7 +71,7 @@ class NightLight extends GObject.Object {
return this.instance; return this.instance;
} }
private async setTemperature(value: number): Promise<void> { private setTemperature(value: number): void {
if(value === this.temperature) return; if(value === this.temperature) return;
if(value > this.maxTemperature || value < 1000) { if(value > this.maxTemperature || value < 1000) {
@@ -93,7 +92,7 @@ class NightLight extends GObject.Object {
)); ));
} }
private async setGamma(value: number) { private setGamma(value: number): void {
if(value === this.gamma) return; if(value === this.gamma) return;
if(value > this.maxGamma || value < 0) { if(value > this.maxGamma || value < 0) {
@@ -114,14 +113,14 @@ class NightLight extends GObject.Object {
)); ));
} }
private applyIdentity(): void { public applyIdentity(): void {
if(this.#identity) return; if(this.#identity) return;
this.#prevGamma = this.#gamma; this.#prevGamma = this.#gamma;
this.#prevTemperature = this.#temperature; this.#prevTemperature = this.#temperature;
this.#identity = true; this.#identity = true;
this.temperature = 6000; this.temperature = this.identityTemperature;
this.gamma = this.maxGamma; this.gamma = this.maxGamma;
} }
@@ -129,8 +128,8 @@ class NightLight extends GObject.Object {
if(!this.#identity) return; if(!this.#identity) return;
this.#identity = false; this.#identity = false;
this.setTemperature(this.#prevTemperature ?? 1000); this.setTemperature(this.#prevTemperature ?? this.identityTemperature);
this.setGamma(this.#prevGamma ?? 100); this.setGamma(this.#prevGamma ?? this.maxGamma);
this.#prevTemperature = null; this.#prevTemperature = null;
this.#prevGamma = null; this.#prevGamma = null;
+7 -5
View File
@@ -12,11 +12,11 @@ export class Stylesheet {
"./style.scss" "./style.scss"
]; ];
public compileSass(): void { public async compileSass(): Promise<void> {
console.log("Stylesheet: Compiling Sass"); console.log("Stylesheet: Compiling Sass");
exec(`bash -c "sass ${this.#styles.map(style => `-I ${style}`).join('\s') exec(`bash -c "sass ${this.#styles.map(style => `-I ${style}`).join('\s')} ${
} ${this.#outputPath.get_path()!}/style.css"`); this.#outputPath.get_path()!}/style.css"`);
} }
public async reapply(cssFilePath: string): Promise<void> { public async reapply(cssFilePath: string): Promise<void> {
@@ -37,8 +37,10 @@ export class Stylesheet {
} }
public async compileApply(): Promise<void> { public async compileApply(): Promise<void> {
this.compileSass(); await this.compileSass().catch((err: Gio.IOErrorEnum) =>
this.reapply(this.#outputPath.get_path()! + "/style.css"); console.error(`Stylesheet: An Error occurred and Sass couldn't be compiled. Stderr:\n${err.message ?
`\t${err.message}\n` : ""}${err.stack}\n`)
).then(() => this.reapply(this.#outputPath.get_path()! + "/style.css"));
} }
public static getDefault(): Stylesheet { public static getDefault(): Stylesheet {
+2
View File
@@ -1,6 +1,8 @@
@use "./colors"; @use "./colors";
.logout-menu { .logout-menu {
background: rgba($color: colors.$bg-translucent-primary, $alpha: .4);
.top { .top {
.time { .time {
font-size: 128px; font-size: 128px;
+20 -20
View File
@@ -1,26 +1,26 @@
// SCSS Variables // SCSS Variables
// Generated by 'wal' // Generated by 'wal'
$wallpaper: "/home/joaov/wallpapers/Kagamine Rin Yellow Tapes.png"; $wallpaper: "/home/joaov/wallpapers/Kita Street.jpeg";
// Special // Special
$background: #190b14; $background: #131a1b;
$foreground: #c5c2c4; $foreground: #c4c5c6;
$cursor: #c5c2c4; $cursor: #c4c5c6;
// Colors // Colors
$color0: #190b14; $color0: #131a1b;
$color1: #905027; $color1: #765236;
$color2: #685345; $color2: #7e6c46;
$color3: #766b0c; $color3: #a07f4c;
$color4: #a78117; $color4: #556c6d;
$color5: #ad9527; $color5: #75817c;
$color6: #425c6e; $color6: #918d7e;
$color7: #998e95; $color7: #90989b;
$color8: #6e5a67; $color8: #5d7171;
$color9: #C06B35; $color9: #9E6E48;
$color10: #8B6F5D; $color10: #A9905E;
$color11: #9E8F11; $color11: #D6AA66;
$color12: #DFAC1F; $color12: #729092;
$color13: #E7C735; $color13: #9CACA6;
$color14: #597B93; $color14: #C2BDA9;
$color15: #c5c2c4; $color15: #c4c5c6;
+13 -7
View File
@@ -4,10 +4,18 @@ import AstalMpris from "gi://AstalMpris";
import { getSymbolicIcon } from "../../scripts/apps"; import { getSymbolicIcon } from "../../scripts/apps";
import { Separator, SeparatorProps } from "../Separator"; import { Separator, SeparatorProps } from "../Separator";
import { Windows } from "../../windows"; import { Windows } from "../../windows";
import { Clipboard } from "../../scripts/clipboard";
<<<<<<< ryo
=======
const playerIcons = {
spotify: "spotify-symbolic",
mpv: "mpv-symbolic",
Clapper: "com.github.rafostar.Clapper-symbolic"
};
>>>>>>> ryo
export function Media(): Gtk.Widget { export function Media(): Gtk.Widget {
const connections: Array<number> = []; const connections: Array<number> = [];
const mediaControlsRevealer: Widget.Revealer = new Widget.Revealer({ const mediaControlsRevealer: Widget.Revealer = new Widget.Revealer({
@@ -26,11 +34,9 @@ export function Media(): Gtk.Widget {
icon: "edit-paste-symbolic" icon: "edit-paste-symbolic"
} as Widget.IconProps), } as Widget.IconProps),
tooltipText: "Copy link to Clipboard", tooltipText: "Copy link to Clipboard",
visible: bind(players[0], "metadata").as((meta) => visible: bind(players[0], "metadata").as((metadata) =>
Boolean(meta["xesam:url"]?.get_string()[0])), metadata["xesam:url"]?.get_string()[0] != null),
onClick: () => Clipboard.getDefault().copyAsync( onClick: () => console.log(players[0].metadata["xesam:url"]?.get_string()[0]!)
players[0].metadata["xesam:url"].get_string()[0]
)
} as Widget.ButtonProps), } as Widget.ButtonProps),
new Widget.Button({ new Widget.Button({
className: "previous", className: "previous",
-1
View File
@@ -73,7 +73,6 @@ class Pages extends Widget.Box {
this.#page = undefined; this.#page = undefined;
timeout(this.#transDuration, () => { timeout(this.#transDuration, () => {
pageRevealer.ref();
this.remove(pageRevealer); this.remove(pageRevealer);
pageRevealer.destroy(); pageRevealer.destroy();
+12 -9
View File
@@ -1,8 +1,8 @@
import { exec, execAsync, GLib, Variable } from "astal"; import { exec, GLib, Variable } from "astal";
import { Gtk, Widget } from "astal/gtk3"; import { Gtk, Widget } from "astal/gtk3";
import AstalHyprland from "gi://AstalHyprland";
import { Windows } from "../../windows"; import { Windows } from "../../windows";
import { Wallpaper } from "../../scripts/wallpaper"; import { Wallpaper } from "../../scripts/wallpaper";
import { execApp } from "../../scripts/apps";
function LockButton(): Widget.Button { function LockButton(): Widget.Button {
@@ -12,7 +12,7 @@ function LockButton(): Widget.Button {
} as Widget.IconProps), } as Widget.IconProps),
onClick: () => { onClick: () => {
Windows.close("control-center"); Windows.close("control-center");
AstalHyprland.get_default().dispatch("exec", "hyprlock"); execApp("hyprlock");
} }
} as Widget.ButtonProps) } as Widget.ButtonProps)
} }
@@ -22,10 +22,10 @@ function ColorPickerButton(): Widget.Button {
image: new Widget.Icon({ image: new Widget.Icon({
icon: "color-select-symbolic" icon: "color-select-symbolic"
} as Widget.IconProps), } as Widget.IconProps),
onClick: () => AstalHyprland.get_default().dispatch( onClick: () => {
"exec", Windows.close("control-center");
"sh $HOME/.config/hypr/scripts/color-picker.sh" execApp("sh $HOME/.config/hypr/scripts/color-picker.sh");
) }
} as Widget.ButtonProps) } as Widget.ButtonProps)
} }
@@ -36,7 +36,7 @@ function ScreenshotButton(): Widget.Button {
} as Widget.IconProps), } as Widget.IconProps),
onClick: () => { onClick: () => {
Windows.close("control-center"); Windows.close("control-center");
execAsync(`sh ${GLib.get_user_config_dir()}/hypr/scripts/screenshot.sh`); execApp(`sh ${GLib.get_user_config_dir()}/hypr/scripts/screenshot.sh`);
} }
} as Widget.ButtonProps); } as Widget.ButtonProps);
} }
@@ -58,7 +58,10 @@ function LogoutButton(): Widget.Button {
image: new Widget.Icon({ image: new Widget.Icon({
icon: "system-shutdown-symbolic" icon: "system-shutdown-symbolic"
} as Widget.IconProps), } as Widget.IconProps),
onClick: () => Windows.open("logout-menu") onClick: () => {
Windows.close("control-center");
Windows.open("logout-menu");
}
} as Widget.ButtonProps); } as Widget.ButtonProps);
} }
+2 -2
View File
@@ -3,10 +3,10 @@ import { Gtk, Widget } from "astal/gtk3";
import AstalBluetooth from "gi://AstalBluetooth"; import AstalBluetooth from "gi://AstalBluetooth";
import { Page, PageButton } from "./Page"; import { Page, PageButton } from "./Page";
import { tr } from "../../../i18n/intl"; import { tr } from "../../../i18n/intl";
import AstalHyprland from "gi://AstalHyprland";
import { Windows } from "../../../windows"; import { Windows } from "../../../windows";
import { Notifications } from "../../../scripts/notifications"; import { Notifications } from "../../../scripts/notifications";
import AstalNotifd from "gi://AstalNotifd"; import AstalNotifd from "gi://AstalNotifd";
import { execApp } from "../../../scripts/apps";
export const BluetoothPage: (() => Page) = () => new Page({ export const BluetoothPage: (() => Page) = () => new Page({
id: "bluetooth", id: "bluetooth",
@@ -42,7 +42,7 @@ export const BluetoothPage: (() => Page) = () => new Page({
title: tr("control_center.pages.more_settings"), title: tr("control_center.pages.more_settings"),
onClick: () => { onClick: () => {
Windows.close("control-center"); Windows.close("control-center");
AstalHyprland.get_default().dispatch("exec", "[float; animation slide right] overskride"); execApp("overskride", "[float; animation slide right]");
} }
}], }],
spacing: 2, spacing: 2,
@@ -21,7 +21,7 @@ export function PageMicrophone(): Page {
className: bind(microphone, "isDefault").as(isDefault => isDefault ? "default" : ""), className: bind(microphone, "isDefault").as(isDefault => isDefault ? "default" : ""),
icon: bind(microphone, "icon").as(icon => icon: bind(microphone, "icon").as(icon =>
Astal.Icon.lookup_icon(icon) ? icon : "audio-input-microphone-symbolic"), Astal.Icon.lookup_icon(icon) ? icon : "audio-input-microphone-symbolic"),
title: bind(microphone, "name").as(name => name ?? "Microphone"), title: bind(microphone, "description").as(desc => desc ?? "Microphone"),
onClick: () => microphone.set_is_default(true), onClick: () => microphone.set_is_default(true),
endWidget: new Widget.Icon({ endWidget: new Widget.Icon({
icon: "object-select-symbolic", icon: "object-select-symbolic",
+6 -6
View File
@@ -4,8 +4,8 @@ import AstalNetwork from "gi://AstalNetwork";
import { bind } from "astal"; import { bind } from "astal";
import NM from "gi://NM"; import NM from "gi://NM";
import { Windows } from "../../../windows"; import { Windows } from "../../../windows";
import AstalHyprland from "gi://AstalHyprland";
import { tr } from "../../../i18n/intl"; import { tr } from "../../../i18n/intl";
import { execApp } from "../../../scripts/apps";
export const PageNetwork: (() => Page) = () => new Page({ export const PageNetwork: (() => Page) = () => new Page({
id: "network", id: "network",
@@ -27,7 +27,7 @@ export const PageNetwork: (() => Page) = () => new Page({
title: tr("control_center.pages.more_settings"), title: tr("control_center.pages.more_settings"),
onClick: () => { onClick: () => {
Windows.close("control-center"); Windows.close("control-center");
AstalHyprland.get_default().dispatch("exec", "[animationstyle gnomed] nm-connection-editor"); execApp("nm-connection-editor", "[animationstyle gnomed]");
} }
}], }],
children: [ children: [
@@ -60,10 +60,10 @@ export const PageNetwork: (() => Page) = () => new Page({
} as Widget.IconProps), } as Widget.IconProps),
onClick: () => { onClick: () => {
Windows.close("control-center"); Windows.close("control-center");
AstalHyprland.get_default().dispatch("exec", execApp(
`[animationstyle gnomed; float] nm-connection-editor --edit ${ `nm-connection-editor --edit ${dev.activeConnection?.connection.get_uuid()}`,
dev.activeConnection?.connection.get_uuid() "[animationstyle gnomed; float]"
}`); );
} }
} as Widget.ButtonProps) } as Widget.ButtonProps)
] ]
@@ -25,7 +25,7 @@ export const PageNightLight: (() => Page) = () => new Page({
value: bind(NightLight.getDefault(), "temperature"), value: bind(NightLight.getDefault(), "temperature"),
tooltipText: bind(NightLight.getDefault(), "temperature").as((temp) => `${temp}K`), tooltipText: bind(NightLight.getDefault(), "temperature").as((temp) => `${temp}K`),
min: 1000, min: 1000,
max: bind(NightLight.getDefault(), "maxTemperature"), max: NightLight.getDefault().maxTemperature,
onDragged: (slider) => onDragged: (slider) =>
NightLight.getDefault().temperature = (Math.floor(slider.value)), NightLight.getDefault().temperature = (Math.floor(slider.value)),
} as Widget.SliderProps), } as Widget.SliderProps),
@@ -42,7 +42,7 @@ export const PageNightLight: (() => Page) = () => new Page({
addSliderMarksFromMinMax(slider, 5, "{}%"); addSliderMarksFromMinMax(slider, 5, "{}%");
}, },
value: bind(NightLight.getDefault(), "gamma"), value: bind(NightLight.getDefault(), "gamma"),
max: bind(NightLight.getDefault(), "maxGamma"), max: NightLight.getDefault().maxGamma,
tooltipText: bind(NightLight.getDefault(), "gamma").as((gamma) => `${gamma}%`), tooltipText: bind(NightLight.getDefault(), "gamma").as((gamma) => `${gamma}%`),
onDragged: (slider) => onDragged: (slider) =>
NightLight.getDefault().gamma = (Math.floor(slider.value)), NightLight.getDefault().gamma = (Math.floor(slider.value)),
+14 -4
View File
@@ -172,7 +172,7 @@ class Page extends Widget.Box {
} }
} }
export function PageButton(props: { export function PageButton({ onDestroy, ...props }: {
className?: string | Binding<string>; className?: string | Binding<string>;
icon?: string | Binding<string>; icon?: string | Binding<string>;
title: string | Binding<string>; title: string | Binding<string>;
@@ -185,7 +185,7 @@ export function PageButton(props: {
tooltipMarkup?: string | Binding<string>; tooltipMarkup?: string | Binding<string>;
}): Gtk.Widget { }): Gtk.Widget {
return new Widget.Box({ return new Widget.Box({
onDestroy: props.onDestroy, onDestroy,
children: [ children: [
new Widget.Button({ new Widget.Button({
onClick: props.onClick, onClick: props.onClick,
@@ -202,17 +202,26 @@ export function PageButton(props: {
className: "icon", className: "icon",
icon: props.icon, icon: props.icon,
visible: props.icon, visible: props.icon,
hexpand: false,
css: "font-size: 20px; margin-right: 6px;" css: "font-size: 20px; margin-right: 6px;"
} as Widget.IconProps), } as Widget.IconProps),
new Widget.Box({ new Widget.Box({
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
expand: true, hexpand: true,
vexpand: false,
children: [ children: [
new Widget.Label({ new Widget.Label({
className: "title", className: "title",
xalign: 0, xalign: 0,
// truncating is not working, so I had to do this
label: (props.title instanceof Binding) ?
props.title.as((title) =>
`${title.substring(0, 35)}${
title.length > 35 ? '…' : ""}`)
: `${props.title.substring(0, 35)}${
props.title.length > 35 ? '…' : ""}`,
tooltipText: props.title,
truncate: true, truncate: true,
label: props.title
} as Widget.LabelProps), } as Widget.LabelProps),
new Widget.Label({ new Widget.Label({
className: "description", className: "description",
@@ -230,6 +239,7 @@ export function PageButton(props: {
visible: (props.endWidget instanceof Binding) ? visible: (props.endWidget instanceof Binding) ?
props.endWidget.as(Boolean) props.endWidget.as(Boolean)
: props.endWidget, : props.endWidget,
halign: Gtk.Align.END,
child: props.endWidget child: props.endWidget
} as Widget.BoxProps) } as Widget.BoxProps)
] ]
+1 -1
View File
@@ -27,7 +27,7 @@ export function PageSound(): Page {
className: bind(speaker, "isDefault").as(isDefault => isDefault ? "default" : ""), className: bind(speaker, "isDefault").as(isDefault => isDefault ? "default" : ""),
icon: bind(speaker, "icon").as(icon => icon: bind(speaker, "icon").as(icon =>
Astal.Icon.lookup_icon(icon)? icon : "audio-card-symbolic"), Astal.Icon.lookup_icon(icon)? icon : "audio-card-symbolic"),
title: speaker.name ?? "Speaker", title: bind(speaker, "description").as(desc => desc ?? "Speaker"),
onClick: () => speaker.set_is_default(true), onClick: () => speaker.set_is_default(true),
endWidget: new Widget.Icon({ endWidget: new Widget.Icon({
icon: "object-select-symbolic", icon: "object-select-symbolic",
@@ -7,19 +7,16 @@ import { TilesPages } from "../Tiles";
import { isInstalled } from "../../../scripts/utils"; import { isInstalled } from "../../../scripts/utils";
import { Widget } from "astal/gtk3"; import { Widget } from "astal/gtk3";
export const TileNightLight = () => isInstalled("hyprsunset") ? export const TileNightLight = () => isInstalled("hyprsunset") ? Tile({
Tile({
title: tr("control_center.tiles.night_light.title"), title: tr("control_center.tiles.night_light.title"),
icon: "weather-clear-night-symbolic", icon: "weather-clear-night-symbolic",
description: Variable.derive([ description: Variable.derive([
bind(NightLight.getDefault(), "temperature"), bind(NightLight.getDefault(), "temperature"),
bind(NightLight.getDefault(), "gamma") bind(NightLight.getDefault(), "gamma")
], (temp, gamma) => ], (temp, gamma) => `${temp === NightLight.getDefault().identityTemperature ?
(temp === 6000 ? tr("control_center.tiles.night_light.default_desc") tr("control_center.tiles.night_light.default_desc") : `${temp}K`} ${
: `${temp}K`) + (gamma < NightLight.getDefault().maxGamma ? gamma < NightLight.getDefault().maxGamma ? `(${gamma}%)` : ""}`
` (${gamma}%)` : "")
)(), )(),
iconSize: 16,
onToggledOff: () => NightLight.getDefault().identity = true, onToggledOff: () => NightLight.getDefault().identity = true,
onToggledOn: () => NightLight.getDefault().identity = false, onToggledOn: () => NightLight.getDefault().identity = false,
enableOnClickMore: true, enableOnClickMore: true,
+8 -6
View File
@@ -18,13 +18,15 @@ export type TileProps = {
} }
export function Tile(props: TileProps): (() => Gtk.Widget) { export function Tile(props: TileProps): (() => Gtk.Widget) {
const toggled = new Variable<boolean>(props.toggleState instanceof Binding ? const subs: Array<() => void> = [];
(props.toggleState.get() || false) : (props.toggleState || false)); const toggled = new Variable<boolean>(((props.toggleState instanceof Binding) ?
props.toggleState.get()
let subscription: () => void; : props.toggleState) ?? false);
if(props?.toggleState instanceof Binding) if(props?.toggleState instanceof Binding)
subscription = props.toggleState.subscribe(val => toggled.set(val || false)); subs.push(props.toggleState.subscribe((state) =>
toggled.set(state ?? false)
));
return () => new Widget.Box({ return () => new Widget.Box({
className: (props.className instanceof Binding) ? className: (props.className instanceof Binding) ?
@@ -44,8 +46,8 @@ export function Tile(props: TileProps): (() => Gtk.Widget) {
expand: true, expand: true,
visible: props.visible, visible: props.visible,
onDestroy: () => { onDestroy: () => {
subs.map(sub => sub?.());
props.onDestroy?.(); props.onDestroy?.();
subscription?.();
}, },
children: [ children: [
new Widget.Button({ new Widget.Button({
+2 -2
View File
@@ -1,6 +1,6 @@
import { GObject, Variable } from "astal"; import { GObject, Variable } from "astal";
import { Astal, Gdk, Gtk, Widget } from "astal/gtk3"; import { Astal, Gdk, Gtk, Widget } from "astal/gtk3";
import { cleanExec, getAppIcon, getApps, getAstalApps } from "../scripts/apps"; import { execApp, getAppIcon, getApps, getAstalApps } from "../scripts/apps";
import AstalApps from "gi://AstalApps"; import AstalApps from "gi://AstalApps";
import { PopupWindow } from "../widget/PopupWindow"; import { PopupWindow } from "../widget/PopupWindow";
@@ -83,7 +83,7 @@ export const AppsWindow = (mon: number): (Widget.Window) => {
button.set_can_focus(false); button.set_can_focus(false);
const openFun = () => { const openFun = () => {
cleanExec(app); execApp(app);
window.close(); window.close();
}; };
+29 -3
View File
@@ -1,8 +1,10 @@
import { Astal, Gdk, Gtk, Widget } from "astal/gtk3"; import { Astal, Gdk, Gtk, Widget } from "astal/gtk3";
import { getDateTime } from "../scripts/time"; import { getDateTime } from "../scripts/time";
import { exec, execAsync, GLib } from "astal"; import { exec, execAsync, Gio, GLib } from "astal";
import { AskPopup } from "../widget/AskPopup"; import { AskPopup } from "../widget/AskPopup";
import { Windows } from "../windows"; import { Windows } from "../windows";
import { Notifications } from "../scripts/notifications";
import AstalNotifd from "gi://AstalNotifd";
const { TOP, LEFT, RIGHT, BOTTOM } = Astal.WindowAnchor; const { TOP, LEFT, RIGHT, BOTTOM } = Astal.WindowAnchor;
@@ -99,8 +101,32 @@ export const LogoutMenu = (mon: number) => new Widget.Window({
title: "Log out", title: "Log out",
text: "Are you sure you want to log out? Your session will be ended.", text: "Are you sure you want to log out? Your session will be ended.",
onAccept: () => { onAccept: () => {
exec(`sh "${GLib.getenv("XDG_CONFIG_HOME")}/hypr/scripts/save-hyprsunset.sh"`); execAsync(
execAsync(`sh -c "loginctl terminate-user ${GLib.getenv("USER") || "$USER"}"`); `sh "${GLib.getenv("XDG_CONFIG_HOME")}/hypr/scripts/save-hyprsunset.sh"`
).finally(() =>
execAsync(`hyprctl dispatch exit`).catch((err: Gio.IOErrorEnum) =>
Notifications.getDefault().sendNotification({
appName: "colorshell",
summary: "Couldn't exit Hyprland",
body: `An error occurred and colorshell couldn't exit Hyprland. Stderr: \n${
err.message ? `${err.message}\n` : ""}${err.stack}`,
urgency: AstalNotifd.Urgency.NORMAL,
actions: [{
text: "Report Issue on colorshell",
onAction: () => execAsync(
`xdg-open https://github.com/retrozinndev/colorshell/issues/new`
).catch((err: Gio.IOErrorEnum) =>
Notifications.getDefault().sendNotification({
appName: "colorshell",
summary: "Couldn't open link",
body: `Do you have \`xdg-utils\` installed? Stderr: \n${
err.message ? `${err.message}\n` : ""}${err.stack}`
})
)
}]
})
)
);
} }
}) })
} as Widget.ButtonProps), } as Widget.ButtonProps),
+3 -3
View File
@@ -5,14 +5,14 @@ function send_notification() {
} }
# Check if user has hyprpicker installed # Check if user has hyprpicker installed
if ! [[ -f /bin/hyprpicker ]]; then if [[ -z $(command -v hyprpicker) ]]; then
send_notification "An error occurred" "Looks like you don't have hyprpicker installed! Try installing it before using the Color Picker tool." send_notification "An error occurred" "Looks like you don't have hyprpicker installed! Try installing it before using the Color Picker tool."
exit 1 exit 1
fi fi
selected_color=$(hyprpicker | tail -n 1 | xargs) selected_color=$(hyprpicker | tail -n 1 | xargs | sed -e 's/ //g')
if ! [[ -z $selected_color ]]; then if [[ ! -z "$selected_color" ]] && [[ ! "$selected_color" == " " ]]; then
wl-copy $selected_color wl-copy $selected_color
send_notification "Selected Color" "The selected color is <span foreground='$selected_color'>$selected_color</span>, it was also copied to your clipboard!" send_notification "Selected Color" "The selected color is <span foreground='$selected_color'>$selected_color</span>, it was also copied to your clipboard!"
fi fi
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# This script executes the provided program with UWSM
# if in usage or launches it normally with hyprctl.
# ---------------
# Licensed under the MIT License
# Made by retrozinndev (João Dias)
# From: https://github.com/retrozinndev/colorshell
if uwsm check is-active; then
hyprctl dispatch exec "uwsm app -- $@" > /dev/null
exit 0
fi
hyprctl dispatch exec "$@" > /dev/null
+5 -5
View File
@@ -6,16 +6,16 @@
exec-once = systemctl enable --user --now hyprpolkitagent # Hyprland's PolKit exec-once = systemctl enable --user --now hyprpolkitagent # Hyprland's PolKit
exec-once = systemctl enable --user --now hypridle exec-once = systemctl enable --user --now hypridle
exec-once = systemctl enable --user --now gnome-keyring-daemon exec-once = systemctl enable --user --now gnome-keyring-daemon
exec-once = wl-paste --type text --watch cliphist store exec-once = $exec wl-paste --type text --watch cliphist store
exec-once = wl-paste --type image --watch cliphist store exec-once = $exec wl-paste --type image --watch cliphist store
# Tools # Tools
exec-once = systemctl enable --user --now hyprsunset exec-once = systemctl enable --user --now hyprsunset
exec-once = systemctl enable --user --now hyprpaper exec-once = systemctl enable --user --now hyprpaper
# Scripts # Scripts
exec-once = sh $XDG_CONFIG_HOME/hypr/scripts/gen-pywal.sh exec-once = $exec sh $XDG_CONFIG_HOME/hypr/scripts/gen-pywal.sh
exec-once = sleep 3 && sh $XDG_CONFIG_HOME/hypr/scripts/load-hyprsunset.sh # wait some time to actually set the filters exec-once = $exec sleep 3 && sh $XDG_CONFIG_HOME/hypr/scripts/load-hyprsunset.sh # wait some time to actually set the filters
# Shell # Shell
exec-once = ags run exec-once = $exec ags run
+10 -8
View File
@@ -1,26 +1,28 @@
# color-shell specific configuration, please don't modify unless you know what you're doing! # color-shell specific configuration, please don't modify unless you know what you're doing!
# `astal` and some `.*ctl` commands don't need $exec (uwsm), since it's just some process communication
bind = $mainMod, SPACE, exec, $menu bind = $mainMod, SPACE, exec, $menu
bind = $mainMod, F11, fullscreen bind = $mainMod, F11, fullscreen
bind = , Print, exec, sh $XDG_CONFIG_HOME/hypr/scripts/screenshot.sh bind = , Print, exec, $exec sh $XDG_CONFIG_HOME/hypr/scripts/screenshot.sh
bind = $mainMod, Print, exec, sh $XDG_CONFIG_HOME/hypr/scripts/screenshot.sh full bind = $mainMod, Print, exec, $exec sh $XDG_CONFIG_HOME/hypr/scripts/screenshot.sh full
# Test-only bind, restarts colorshell # restarts colorshell
bind = $mainMod, F7, exec, ags request reload bind = $mainMod, F7, exec, astal reload
bind = $mainMod, K, exec, $terminal bind = $mainMod, K, exec, $exec $terminal
bind = $mainMod, Q, killactive bind = $mainMod, Q, killactive
bind = $mainMod, E, exec, $fm bind = $mainMod, E, exec, $exec $fm
bind = $mainMod, F, togglefloating bind = $mainMod, F, togglefloating
bind = $mainMod, P, pseudo, bind = $mainMod, P, pseudo,
bind = $mainMod, J, togglesplit bind = $mainMod, J, togglesplit
bind = $mainMod, N, exec, astal toggle control-center bind = $mainMod, N, exec, astal toggle control-center
bind = $mainMod, M, exec, astal toggle center-window bind = $mainMod, M, exec, astal toggle center-window
bind = $mainMod, L, exec, hyprlock bind = $mainMod, L, exec, $exec hyprlock
bind = $mainMod, V, exec, astal runner '>' || sh $XDG_CONFIG_HOME/hypr/scripts/clipboard-menu.sh bind = $mainMod, V, exec, astal runner '>' || $exec sh $XDG_CONFIG_HOME/hypr/scripts/clipboard-menu.sh
bind = $mainMod, W, exec, astal runner '##' bind = $mainMod, W, exec, astal runner '##'
# bind = $mainMod, $mainMod_L, exec, astal toggle apps-window # bind = $mainMod, $mainMod_L, exec, astal toggle apps-window
+1 -1
View File
@@ -25,5 +25,5 @@ env = QT_QPA_PLATFORMTHEME, qt5ct
env = QT_AUTO_SCREEN_SCALE_FACTOR, 1 env = QT_AUTO_SCREEN_SCALE_FACTOR, 1
# Others # Others
env = ADW_DISABLE_PORTAL, 1 # Fixes prefer-dark theme setting in some flatpak apps env = ADW_DISABLE_PORTAL, 1 # Fixes prefer-dark setting in some gtk flatpak apps
env = WALLPAPERS, $HOME/wallpapers env = WALLPAPERS, $HOME/wallpapers
+1
View File
@@ -28,6 +28,7 @@ windowrule = animation gnomed, class:hyprpolkitagent
windowrule = animation slide right, class:org.pulseaudio.pavucontrol windowrule = animation slide right, class:org.pulseaudio.pavucontrol
windowrule = animation slide right, class:io.github.kaii_lb.Overskride windowrule = animation slide right, class:io.github.kaii_lb.Overskride
windowrule = animation gnomed, class:xdg-desktop-portal.* windowrule = animation gnomed, class:xdg-desktop-portal.*
windowrule = animation gnomed, class:hyprsysteminfo
layerrule = animation fade, selection layerrule = animation fade, selection
layerrule = animation fade, hyprpicker layerrule = animation fade, hyprpicker
+4 -2
View File
@@ -6,8 +6,10 @@
############### ###############
# Wiki: https://wiki.hyprland.org/Hypr-Ecosystem/hyprlang#defining-variables # Wiki: https://wiki.hyprland.org/Hypr-Ecosystem/hyprlang#defining-variables
# Use this variable to execute apps dinamically (runs with uwsm if being used by compositor)
$exec = sh $XDG_CONFIG_HOME/hypr/scripts/exec.sh
$mainMod = SUPER $mainMod = SUPER
$terminal = kitty $terminal = kitty
$fm = nautilus $fm = nautilus
$menu = astal runner || anyrun $menu = astal runner
$dmenu = anyrun --plugins libstdin.so