diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-03-15 13:53:53 +1100 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-03-15 13:53:53 +1100 |
| commit | dddc7382a59009b6a0e7e2322559efd9087c5acf (patch) | |
| tree | 1055ed46d3cc515c7aaef158d1f7e2bd6e028c84 | |
| parent | notifs: make dnd actually work (diff) | |
| download | caelestia-shell-dddc7382a59009b6a0e7e2322559efd9087c5acf.tar.gz caelestia-shell-dddc7382a59009b6a0e7e2322559efd9087c5acf.tar.bz2 caelestia-shell-dddc7382a59009b6a0e7e2322559efd9087c5acf.zip | |
launcher: wallpaper random by category
| -rw-r--r-- | scss/launcher.scss | 13 | ||||
| -rw-r--r-- | src/modules/launcher/actions.tsx | 47 | ||||
| -rw-r--r-- | src/services/wallpapers.ts | 39 |
3 files changed, 80 insertions, 19 deletions
diff --git a/scss/launcher.scss b/scss/launcher.scss index 87854f4..590fe82 100644 --- a/scss/launcher.scss +++ b/scss/launcher.scss @@ -188,6 +188,19 @@ .thumbnail { @include lib.rounded(10); + + & > * { + background-size: cover; + background-position: center; + + &:first-child { + @include lib.rounded(10, $tr: 0, $br: 0); + } + + &:last-child { + @include lib.rounded(10, $tl: 0, $bl: 0); + } + } } } diff --git a/src/modules/launcher/actions.tsx b/src/modules/launcher/actions.tsx index 05005a4..4ebabfb 100644 --- a/src/modules/launcher/actions.tsx +++ b/src/modules/launcher/actions.tsx @@ -1,7 +1,7 @@ import { Apps } from "@/services/apps"; import Palette from "@/services/palette"; import Schemes, { type Colours } from "@/services/schemes"; -import Wallpapers from "@/services/wallpapers"; +import Wallpapers, { type ICategory, type IWallpaper } from "@/services/wallpapers"; import { basename } from "@/utils/strings"; import { notify } from "@/utils/system"; import { setupCustomTooltip, type FlowBox } from "@/utils/widgets"; @@ -285,7 +285,7 @@ const Scheme = ({ scheme, name, colours }: { scheme?: string; name: string; colo ); }; -const Wallpaper = ({ path, thumbnail }: { path: string; thumbnail?: string }) => ( +const Wallpaper = ({ path, thumbnail }: IWallpaper) => ( <Gtk.FlowBoxChild visible canFocus={false}> <button className="result" @@ -307,6 +307,32 @@ const Wallpaper = ({ path, thumbnail }: { path: string; thumbnail?: string }) => </Gtk.FlowBoxChild> ); +const Category = ({ path, wallpapers }: ICategory) => ( + <Gtk.FlowBoxChild visible canFocus={false}> + <button + className="result" + cursor="pointer" + onClicked={() => { + execAsync(`caelestia wallpaper -d ${path}`).catch(console.error); + close(); + }} + setup={self => setupCustomTooltip(self, path.replace(HOME, "~"))} + > + <box + vertical={config.wallpaper.style.get() !== "compact"} + className={`wallpaper ${config.wallpaper.style.get()}`} + > + <box className="thumbnail"> + {wallpapers.slice(0, 3).map(w => ( + <box hexpand css={"background-image: url('" + (w.thumbnail ?? w.path) + "');"} /> + ))} + </box> + <label truncate label={basename(path)} /> + </box> + </button> + </Gtk.FlowBoxChild> +); + @register() export default class Actions extends Widget.Box implements LauncherContent { #map: ActionMap; @@ -348,9 +374,12 @@ export default class Actions extends Widget.Box implements LauncherContent { } } } else if (action === "wallpaper") { - const wallpaper = args[1] ?? ""; - for (const { obj } of fuzzysort.go(wallpaper, Wallpapers.get_default().list, { all: true, key: "path" })) - this.#content.add(<Wallpaper {...obj} />); + const random = args[1].toLowerCase() === "random"; + const term = (random ? args[2] : args[1]) ?? ""; + const list = random ? Wallpapers.get_default().categories : Wallpapers.get_default().list; + + for (const { obj } of fuzzysort.go(term, list, { all: true, key: "path" })) + this.#content.add(random ? <Category {...(obj as ICategory)} /> : <Wallpaper {...obj} />); } else { const list = this.#list.filter( a => this.#map[a].available?.() ?? !config.disabledActions.get().includes(a) @@ -364,11 +393,9 @@ export default class Actions extends Widget.Box implements LauncherContent { const args = search.split(" "); const action = args[0].slice(1).toLowerCase(); - if ((action === "scheme" || action === "wallpaper") && args[1].toLowerCase() === "random") { - execAsync(`caelestia ${action}`).catch(console.error); + if (action === "scheme" && args[1].toLowerCase() === "random") { + execAsync(`caelestia scheme`).catch(console.error); close(); - } - - this.#content.get_child_at_index(0)?.get_child()?.activate(); + } else this.#content.get_child_at_index(0)?.get_child()?.activate(); } } diff --git a/src/services/wallpapers.ts b/src/services/wallpapers.ts index 9a4e5bb..87a9c62 100644 --- a/src/services/wallpapers.ts +++ b/src/services/wallpapers.ts @@ -3,11 +3,16 @@ import { monitorDirectory } from "@/utils/system"; import { execAsync, GLib, GObject, property, register } from "astal"; import { wallpapers as config } from "config"; -export interface Wallpaper { +export interface IWallpaper { path: string; thumbnail?: string; } +export interface ICategory { + path: string; + wallpapers: IWallpaper[]; +} + @register({ GTypeName: "Wallpapers" }) export default class Wallpapers extends GObject.Object { static instance: Wallpapers; @@ -19,13 +24,19 @@ export default class Wallpapers extends GObject.Object { #thumbnailDir = `${CACHE}/thumbnails`; - #list: Wallpaper[] = []; + #list: IWallpaper[] = []; + #categories: ICategory[] = []; @property(Object) get list() { return this.#list; } + @property(Object) + get categories() { + return this.#categories; + } + async #thumbnail(path: string) { const dir = path.slice(1, path.lastIndexOf("/")).replaceAll("/", "-"); const thumbPath = `${this.#thumbnailDir}/${dir}-${basename(path)}.jpg`; @@ -33,20 +44,30 @@ export default class Wallpapers extends GObject.Object { return thumbPath; } + #listDir(path: { path: string; recursive: boolean }, type: "f" | "d") { + const absPath = path.path.replace("~", HOME); + const maxDepth = path.recursive ? "" : "-maxdepth 1"; + return execAsync(`find ${absPath} ${maxDepth} -path '*/.*' -prune -o -type ${type} -print`); + } + async update() { const results = await Promise.allSettled( - config.paths - .get() - .map(p => execAsync(`find ${p.path.replace("~", HOME)}/ ${p.recursive ? "" : "-maxdepth 1"} -type f`)) + config.paths.get().map(async p => ({ path: p, files: await this.#listDir(p, "f") })) ); - const files = results - .filter(r => r.status === "fulfilled") - .map(r => r.value.replaceAll("\n", " ")) - .join(" "); + const successes = results.filter(r => r.status === "fulfilled").map(r => r.value); + + const files = successes.map(r => r.files.replaceAll("\n", " ")).join(" "); const list = (await execAsync(["fish", "-c", `identify -ping -format '%i\n' ${files} ; true`])).split("\n"); this.#list = await Promise.all(list.map(async p => ({ path: p, thumbnail: await this.#thumbnail(p) }))); this.notify("list"); + + const categories = await Promise.all(successes.map(r => this.#listDir(r.path, "d"))); + this.#categories = categories + .flatMap(c => c.split("\n")) + .map(c => ({ path: c, wallpapers: this.#list.filter(w => w.path.startsWith(c)) })) + .filter(c => c.wallpapers.length > 0); + this.notify("categories"); } constructor() { |