Compare commits

...

7 Commits

Author SHA1 Message Date
tux
0c7610355f Merge pull request #1 from kkanden/patch-1
Fix typo in README
2025-10-08 17:50:04 +05:30
oliwia
0c1ac689cf fix: typo 2025-10-07 13:35:06 +02:00
tux
98203af3e4 feat: add notification timeout manager 2025-10-07 03:25:48 +05:30
tux
416f2004af chore: update image 2025-10-07 03:07:12 +05:30
tux
d185a7e694 feat: add wallpaper-manager 2025-10-07 01:58:52 +05:30
tux
410ee29aa1 docs: update README.md 2025-10-06 18:37:27 +05:30
tux
c9cb1a411e feat(gallery): add latest image 2025-10-06 18:34:38 +05:30
8 changed files with 211 additions and 2 deletions

View File

@@ -8,7 +8,7 @@
<img alt="GitHub commit activity" src="https://img.shields.io/github/commit-activity/m/tuxdotrs/tpanel"> <img alt="GitHub commit activity" src="https://img.shields.io/github/commit-activity/m/tuxdotrs/tpanel">
</p> </p>
![full](https://raw.githubusercontent.com/tuxdotrs/tpanel/refs/heads/main/assets/gallery/full.png) ![latest](https://raw.githubusercontent.com/tuxdotrs/tpanel/refs/heads/main/assets/gallery/latest.png)
## Installation ## Installation
@@ -34,3 +34,5 @@ environment.systemPackages = [ inputs.tpanel.packages.${system}.default ];
# Add this in your HomeManager config # Add this in your HomeManager config
home.packages = [ inputs.tpanel.packages.${system}.default ]; home.packages = [ inputs.tpanel.packages.${system}.default ];
``` ```
## Outdated Screenshot
![full](https://raw.githubusercontent.com/tuxdotrs/tpanel/refs/heads/main/assets/gallery/full.png)

BIN
assets/gallery/latest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

@@ -0,0 +1,30 @@
@use "./_variable.scss" as *;
@use "sass:math";
@use "sass:list";
window.wallpaper-manager {
background: $bg-color;
color: $fg-color;
min-width: 400px;
margin: 10px;
padding: 20px;
border-radius: $rounded;
.button {
border-radius: $rounded;
opacity: 0.5;
&:hover,
&:focus {
opacity: 1;
}
}
picture {
border-radius: $rounded;
&:hover {
background: $inactive-color;
}
}
}

View File

@@ -12,3 +12,6 @@
// control center // control center
@use "./_control-center.scss"; @use "./_control-center.scss";
// wallpaper manager
@use "./_wallpaper-manager.scss";

View File

@@ -0,0 +1,50 @@
import GLib from "gi://GLib";
type TimeoutManager = {
setupTimeout: () => void;
clearTimeout: () => void;
handleHover: () => void;
handleHoverLost: () => void;
cleanup: () => void;
};
export const createTimeoutManager = (
dismissCallback: () => void,
timeoutDelay: number,
): TimeoutManager => {
let isHovered = false;
let timeoutId: number | null = null;
const clearTimeout = () => {
if (timeoutId !== null) {
GLib.source_remove(timeoutId);
timeoutId = null;
}
};
const setupTimeout = () => {
clearTimeout();
if (!isHovered) {
timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeoutDelay, () => {
clearTimeout();
dismissCallback();
return GLib.SOURCE_REMOVE;
});
}
};
return {
setupTimeout,
clearTimeout,
handleHover: () => {
isHovered = true;
clearTimeout();
},
handleHoverLost: () => {
isHovered = false;
setupTimeout();
},
cleanup: clearTimeout,
};
};

View File

@@ -3,6 +3,8 @@ import Adw from "gi://Adw";
import AstalNotifd from "gi://AstalNotifd"; import AstalNotifd from "gi://AstalNotifd";
import GLib from "gi://GLib"; import GLib from "gi://GLib";
import Pango from "gi://Pango"; import Pango from "gi://Pango";
import { createTimeoutManager } from "./manager";
import { onCleanup, onMount } from "ags";
const isIcon = (icon?: string | null) => { const isIcon = (icon?: string | null) => {
const iconTheme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()!); const iconTheme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()!);
@@ -33,7 +35,20 @@ const urgency = (n: AstalNotifd.Notification) => {
const { VERTICAL } = Gtk.Orientation; const { VERTICAL } = Gtk.Orientation;
const { START, END, CENTER } = Gtk.Align; const { START, END, CENTER } = Gtk.Align;
// Keep track of notification validity
const TIMEOUT_DELAY = 3000;
export const Notification = ({ n }: { n: AstalNotifd.Notification }) => { export const Notification = ({ n }: { n: AstalNotifd.Notification }) => {
const timeoutManager = createTimeoutManager(() => n.dismiss(), TIMEOUT_DELAY);
onMount(() => {
timeoutManager.setupTimeout();
});
onCleanup(() => {
timeoutManager.cleanup();
});
return ( return (
<Adw.Clamp maximumSize={400}> <Adw.Clamp maximumSize={400}>
<box <box
@@ -42,6 +57,11 @@ export const Notification = ({ n }: { n: AstalNotifd.Notification }) => {
orientation={VERTICAL} orientation={VERTICAL}
spacing={20} spacing={20}
> >
<Gtk.EventControllerMotion
onEnter={() => timeoutManager.handleHover()}
onLeave={() => timeoutManager.handleHoverLost()}
/>
<box class="header" spacing={10}> <box class="header" spacing={10}>
{(n.appIcon || isIcon(n.desktopEntry)) && ( {(n.appIcon || isIcon(n.desktopEntry)) && (
<image <image

View File

@@ -0,0 +1,103 @@
import { Astal, Gdk, Gtk } from "ags/gtk4";
import app from "ags/gtk4/app";
import { exec } from "ags/process";
import Gio from "gi://Gio";
import GLib from "gi://GLib";
export const WINDOW_NAME = "wallpaper-manager";
// @TODO wallpaper cache
const wallpaperPath = `/home/tux/Wallpapers/new`;
const imageFormats = [".jpeg", ".jpg", ".webp", ".png"];
export const WallpaperManager = (gdkmonitor: Gdk.Monitor) => {
const { TOP, BOTTOM, LEFT } = Astal.WindowAnchor;
const { VERTICAL } = Gtk.Orientation;
const wallpaperList = getWallpaperList(wallpaperPath);
return (
<window
name={WINDOW_NAME}
cssClasses={["wallpaper-manager"]}
gdkmonitor={gdkmonitor}
application={app}
keymode={Astal.Keymode.ON_DEMAND}
anchor={TOP | BOTTOM | LEFT}
>
<Gtk.EventControllerKey onKeyPressed={onKey} />
<scrolledwindow>
<box orientation={VERTICAL} spacing={20}>
{wallpaperList.map((wall) => (
<button
cssClasses={["button"]}
cursor={Gdk.Cursor.new_from_name("pointer", null)}
onClicked={() => setWallpaper(wall)}
>
<Gtk.Picture
file={Gio.file_new_for_path(`${wallpaperPath}/${wall}`)}
heightRequest={200}
widthRequest={200}
hexpand
vexpand
cssClasses={["wallpaper-picture"]}
contentFit={Gtk.ContentFit.COVER}
/>
</button>
))}
</box>
</scrolledwindow>
</window>
);
};
const onKey = (
_e: Gtk.EventControllerKey,
keyval: number,
_: number,
mod: number,
) => {
if (keyval === Gdk.KEY_Escape) {
app.toggle_window(WINDOW_NAME);
return;
}
};
function getWallpaperList(path: string) {
const dir = Gio.file_new_for_path(path);
const fileEnum = dir.enumerate_children(
"standard::name",
Gio.FileQueryInfoFlags.NONE,
null,
);
const files: string[] = [];
let i = fileEnum.next_file(null);
while (i) {
let fileName = i.get_name();
if (imageFormats.some((fmt) => fileName.endsWith(fmt))) {
files.push(fileName);
}
i = fileEnum.next_file(null);
}
return files;
}
const setWallpaper = (name: string) => {
const hyprctl = GLib.find_program_in_path("hyprctl");
const imagePath = `${wallpaperPath}/${name}`;
if (!hyprctl) return;
const preloadedWalls = exec([hyprctl, "hyprpaper", "listloaded"]);
const nWall = preloadedWalls.split("\n").length;
console.log(nWall);
if (nWall >= 5) {
exec([hyprctl, "hyprpaper", "unload", "all"]);
}
exec([hyprctl, "hyprpaper", "preload", imagePath]);
exec([hyprctl, "hyprpaper", "wallpaper", `,${imagePath}`]);
app.toggle_window(WINDOW_NAME);
};

View File

@@ -2,5 +2,6 @@ import { Bar } from "./widgets/bar";
import { Launcher } from "./widgets/launcher"; import { Launcher } from "./widgets/launcher";
import { Notifications } from "./widgets/notifications"; import { Notifications } from "./widgets/notifications";
import { ControlCenter } from "./widgets/control-center"; import { ControlCenter } from "./widgets/control-center";
import { WallpaperManager } from "./widgets/wallpaper-manager";
export default [Bar, Launcher, Notifications, ControlCenter]; export default [Bar, Launcher, Notifications, ControlCenter, WallpaperManager];