summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-03-01 19:08:15 +1100
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-03-01 19:08:15 +1100
commit31138ffd9348990fc3221352fc40d48dfcd59141 (patch)
tree14083dcd472354762d4e1c738adada9652ff05de
parentlauncher: change window colour (diff)
downloadcaelestia-shell-31138ffd9348990fc3221352fc40d48dfcd59141.tar.gz
caelestia-shell-31138ffd9348990fc3221352fc40d48dfcd59141.tar.bz2
caelestia-shell-31138ffd9348990fc3221352fc40d48dfcd59141.zip
launcher: scheme autocomplete
-rw-r--r--app.tsx6
-rw-r--r--scss/launcher.scss28
-rw-r--r--src/modules/launcher/actions.tsx85
-rw-r--r--src/services/schemes.ts44
4 files changed, 150 insertions, 13 deletions
diff --git a/app.tsx b/app.tsx
index 0739d01..d97d41d 100644
--- a/app.tsx
+++ b/app.tsx
@@ -7,8 +7,9 @@ import Session from "@/modules/session";
import Monitors from "@/services/monitors";
import Palette from "@/services/palette";
import Players from "@/services/players";
+import Schemes from "@/services/schemes";
import type PopupWindow from "@/widgets/popupwindow";
-import { execAsync, writeFileAsync } from "astal";
+import { execAsync, idle, writeFileAsync } from "astal";
import { App } from "astal/gtk3";
import { initConfig, updateConfig } from "config";
@@ -38,6 +39,9 @@ App.start({
Monitors.get_default().forEach(m => <Bar monitor={m} />);
<Popdowns />;
+ // Init services
+ idle(() => Schemes.get_default());
+
console.log(`Caelestia started in ${Date.now() - now}ms`);
},
requestHandler(request, res) {
diff --git a/scss/launcher.scss b/scss/launcher.scss
index 7c775b7..49f09c8 100644
--- a/scss/launcher.scss
+++ b/scss/launcher.scss
@@ -125,4 +125,32 @@
background-color: scheme.$surface1;
}
}
+
+ .swatches {
+ @include lib.spacing(3);
+ }
+
+ .swatch {
+ @include lib.rounded(100);
+
+ min-width: lib.s(16);
+ min-height: lib.s(16);
+
+ &.big {
+ min-height: lib.s(32);
+
+ &.left {
+ @include lib.border(scheme.$overlay0, 0.3);
+
+ border-right: none;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ }
+
+ &.right {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ }
+ }
+ }
}
diff --git a/src/modules/launcher/actions.tsx b/src/modules/launcher/actions.tsx
index 52910ea..75f1092 100644
--- a/src/modules/launcher/actions.tsx
+++ b/src/modules/launcher/actions.tsx
@@ -1,4 +1,6 @@
import { Apps } from "@/services/apps";
+import type { IPalette } from "@/services/palette";
+import Schemes from "@/services/schemes";
import { notify } from "@/utils/system";
import { setupCustomTooltip, type FlowBox } from "@/utils/widgets";
import { execAsync, GLib, readFile, register, type Variable } from "astal";
@@ -19,6 +21,11 @@ interface ActionMap {
[k: string]: IAction;
}
+const autocomplete = (entry: Widget.Entry, action: string) => {
+ entry.set_text(`${config.actionPrefix.get()}${action} `);
+ entry.set_position(-1);
+};
+
const actions = (mode: Variable<Mode>, entry: Widget.Entry): ActionMap => ({
apps: {
icon: "apps",
@@ -62,27 +69,32 @@ const actions = (mode: Variable<Mode>, entry: Widget.Entry): ActionMap => ({
description: "Change the current colour scheme",
action: (...args) => {
// If no args, autocomplete cmd
- if (args.length === 0) {
- entry.set_text(`${config.actionPrefix.get()}scheme `);
- entry.set_position(-1);
- return;
- }
+ if (args.length === 0) return autocomplete(entry, "scheme");
execAsync(`caelestia scheme ${args[0]}`).catch(console.error);
close();
},
},
+ wallpaper: {
+ icon: "image",
+ name: "Wallpaper",
+ description: "Change the current wallpaper",
+ action: (...args) => {
+ // If no args, autocomplete cmd
+ if (args.length === 0) return autocomplete(entry, "wallpaper");
+
+ if (args[0] === "random") execAsync("caelestia wallpaper").catch(console.error);
+ else execAsync(`caelestia wallpaper -f ${args[0]}`).catch(console.error);
+ close();
+ },
+ },
todo: {
icon: "checklist",
name: "Todo",
description: "Create a todo in Todoist",
action: (...args) => {
// If no args, autocomplete cmd
- if (args.length === 0) {
- entry.set_text(`${config.actionPrefix.get()}todo `);
- entry.set_position(-1);
- return;
- }
+ if (args.length === 0) return autocomplete(entry, "todo");
// If tod not installed, notify
if (!GLib.find_program_in_path("tod")) {
@@ -165,6 +177,47 @@ const Action = ({ args, icon, name, description, action }: IAction & { args: str
</Gtk.FlowBoxChild>
);
+const Swatch = ({ colour }: { colour: string }) => <box className="swatch" css={"background-color: " + colour + ";"} />;
+
+const Scheme = ({ name, colours }: { name: string; colours: IPalette }) => (
+ <Gtk.FlowBoxChild visible canFocus={false}>
+ <button
+ className="result"
+ cursor="pointer"
+ onClicked={() => {
+ execAsync(`caelestia scheme ${name}`).catch(console.error);
+ close();
+ }}
+ >
+ <box>
+ <box valign={Gtk.Align.CENTER}>
+ <box className="swatch big left" css={"background-color: " + colours.base + ";"} />
+ <box className="swatch big right" css={"background-color: " + colours.accent + ";"} />
+ </box>
+ <box vertical className="has-sublabel">
+ <label truncate xalign={0} label={name} />
+ <box className="swatches">
+ <Swatch colour={colours.rosewater} />
+ <Swatch colour={colours.flamingo} />
+ <Swatch colour={colours.pink} />
+ <Swatch colour={colours.mauve} />
+ <Swatch colour={colours.red} />
+ <Swatch colour={colours.maroon} />
+ <Swatch colour={colours.peach} />
+ <Swatch colour={colours.yellow} />
+ <Swatch colour={colours.green} />
+ <Swatch colour={colours.teal} />
+ <Swatch colour={colours.sky} />
+ <Swatch colour={colours.sapphire} />
+ <Swatch colour={colours.blue} />
+ <Swatch colour={colours.lavender} />
+ </box>
+ </box>
+ </box>
+ </button>
+ </Gtk.FlowBoxChild>
+);
+
@register()
export default class Actions extends Widget.Box implements LauncherContent {
#map: ActionMap;
@@ -190,8 +243,16 @@ export default class Actions extends Widget.Box implements LauncherContent {
updateContent(search: string): void {
this.#content.foreach(c => c.destroy());
const args = search.split(" ");
- for (const { target } of fuzzysort.go(args[0].slice(1), this.#list, { all: true }))
- this.#content.add(<Action {...this.#map[target]} args={args.slice(1)} />);
+ const action = args[0].slice(1);
+
+ if (action === "scheme") {
+ const scheme = args[1] ?? "";
+ for (const { target } of fuzzysort.go(scheme, Object.keys(Schemes.get_default().map), { all: true }))
+ this.#content.add(<Scheme name={target} colours={Schemes.get_default().map[target]} />);
+ } else {
+ for (const { target } of fuzzysort.go(action, this.#list, { all: true }))
+ this.#content.add(<Action {...this.#map[target]} args={args.slice(1)} />);
+ }
}
handleActivate(): void {
diff --git a/src/services/schemes.ts b/src/services/schemes.ts
new file mode 100644
index 0000000..07d6ded
--- /dev/null
+++ b/src/services/schemes.ts
@@ -0,0 +1,44 @@
+import { execAsync, GLib, GObject, monitorFile, property, readFileAsync, register } from "astal";
+import type { IPalette } from "./palette";
+
+const DATA = `${GLib.get_user_data_dir()}/caelestia`;
+
+@register({ GTypeName: "Schemes" })
+export default class Schemes extends GObject.Object {
+ static instance: Schemes;
+ static get_default() {
+ if (!this.instance) this.instance = new Schemes();
+
+ return this.instance;
+ }
+
+ #map: { [k: string]: IPalette } = {};
+
+ @property(Object)
+ get map() {
+ return this.#map;
+ }
+
+ #schemePathToName(path: string) {
+ return path.slice(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
+ }
+
+ async parseScheme(path: string) {
+ const schemeColours = (await readFileAsync(path)).split("\n").map(l => l.split(" "));
+ return schemeColours.reduce((acc, [name, hex]) => ({ ...acc, [name]: `#${hex}` }), {} as IPalette);
+ }
+
+ async update() {
+ const schemes = await execAsync(`find ${DATA}/scripts/data/schemes/ -type f`);
+ for (const scheme of schemes.split("\n"))
+ this.#map[this.#schemePathToName(scheme)] = await this.parseScheme(scheme);
+ this.notify("map");
+ }
+
+ constructor() {
+ super();
+
+ this.update().catch(console.error);
+ monitorFile(`${DATA}/scripts/data/schemes`, () => this.update().catch(console.error));
+ }
+}