launcher: scheme autocomplete
This commit is contained in:
parent
4b9c9aee9c
commit
31138ffd93
4 changed files with 150 additions and 13 deletions
6
app.tsx
6
app.tsx
|
|
@ -7,8 +7,9 @@ import Session from "@/modules/session";
|
||||||
import Monitors from "@/services/monitors";
|
import Monitors from "@/services/monitors";
|
||||||
import Palette from "@/services/palette";
|
import Palette from "@/services/palette";
|
||||||
import Players from "@/services/players";
|
import Players from "@/services/players";
|
||||||
|
import Schemes from "@/services/schemes";
|
||||||
import type PopupWindow from "@/widgets/popupwindow";
|
import type PopupWindow from "@/widgets/popupwindow";
|
||||||
import { execAsync, writeFileAsync } from "astal";
|
import { execAsync, idle, writeFileAsync } from "astal";
|
||||||
import { App } from "astal/gtk3";
|
import { App } from "astal/gtk3";
|
||||||
import { initConfig, updateConfig } from "config";
|
import { initConfig, updateConfig } from "config";
|
||||||
|
|
||||||
|
|
@ -38,6 +39,9 @@ App.start({
|
||||||
Monitors.get_default().forEach(m => <Bar monitor={m} />);
|
Monitors.get_default().forEach(m => <Bar monitor={m} />);
|
||||||
<Popdowns />;
|
<Popdowns />;
|
||||||
|
|
||||||
|
// Init services
|
||||||
|
idle(() => Schemes.get_default());
|
||||||
|
|
||||||
console.log(`Caelestia started in ${Date.now() - now}ms`);
|
console.log(`Caelestia started in ${Date.now() - now}ms`);
|
||||||
},
|
},
|
||||||
requestHandler(request, res) {
|
requestHandler(request, res) {
|
||||||
|
|
|
||||||
|
|
@ -125,4 +125,32 @@
|
||||||
background-color: scheme.$surface1;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import { Apps } from "@/services/apps";
|
import { Apps } from "@/services/apps";
|
||||||
|
import type { IPalette } from "@/services/palette";
|
||||||
|
import Schemes from "@/services/schemes";
|
||||||
import { notify } from "@/utils/system";
|
import { notify } from "@/utils/system";
|
||||||
import { setupCustomTooltip, type FlowBox } from "@/utils/widgets";
|
import { setupCustomTooltip, type FlowBox } from "@/utils/widgets";
|
||||||
import { execAsync, GLib, readFile, register, type Variable } from "astal";
|
import { execAsync, GLib, readFile, register, type Variable } from "astal";
|
||||||
|
|
@ -19,6 +21,11 @@ interface ActionMap {
|
||||||
[k: string]: IAction;
|
[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 => ({
|
const actions = (mode: Variable<Mode>, entry: Widget.Entry): ActionMap => ({
|
||||||
apps: {
|
apps: {
|
||||||
icon: "apps",
|
icon: "apps",
|
||||||
|
|
@ -62,27 +69,32 @@ const actions = (mode: Variable<Mode>, entry: Widget.Entry): ActionMap => ({
|
||||||
description: "Change the current colour scheme",
|
description: "Change the current colour scheme",
|
||||||
action: (...args) => {
|
action: (...args) => {
|
||||||
// If no args, autocomplete cmd
|
// If no args, autocomplete cmd
|
||||||
if (args.length === 0) {
|
if (args.length === 0) return autocomplete(entry, "scheme");
|
||||||
entry.set_text(`${config.actionPrefix.get()}scheme `);
|
|
||||||
entry.set_position(-1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
execAsync(`caelestia scheme ${args[0]}`).catch(console.error);
|
execAsync(`caelestia scheme ${args[0]}`).catch(console.error);
|
||||||
close();
|
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: {
|
todo: {
|
||||||
icon: "checklist",
|
icon: "checklist",
|
||||||
name: "Todo",
|
name: "Todo",
|
||||||
description: "Create a todo in Todoist",
|
description: "Create a todo in Todoist",
|
||||||
action: (...args) => {
|
action: (...args) => {
|
||||||
// If no args, autocomplete cmd
|
// If no args, autocomplete cmd
|
||||||
if (args.length === 0) {
|
if (args.length === 0) return autocomplete(entry, "todo");
|
||||||
entry.set_text(`${config.actionPrefix.get()}todo `);
|
|
||||||
entry.set_position(-1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If tod not installed, notify
|
// If tod not installed, notify
|
||||||
if (!GLib.find_program_in_path("tod")) {
|
if (!GLib.find_program_in_path("tod")) {
|
||||||
|
|
@ -165,6 +177,47 @@ const Action = ({ args, icon, name, description, action }: IAction & { args: str
|
||||||
</Gtk.FlowBoxChild>
|
</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()
|
@register()
|
||||||
export default class Actions extends Widget.Box implements LauncherContent {
|
export default class Actions extends Widget.Box implements LauncherContent {
|
||||||
#map: ActionMap;
|
#map: ActionMap;
|
||||||
|
|
@ -190,9 +243,17 @@ export default class Actions extends Widget.Box implements LauncherContent {
|
||||||
updateContent(search: string): void {
|
updateContent(search: string): void {
|
||||||
this.#content.foreach(c => c.destroy());
|
this.#content.foreach(c => c.destroy());
|
||||||
const args = search.split(" ");
|
const args = search.split(" ");
|
||||||
for (const { target } of fuzzysort.go(args[0].slice(1), this.#list, { all: true }))
|
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)} />);
|
this.#content.add(<Action {...this.#map[target]} args={args.slice(1)} />);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleActivate(): void {
|
handleActivate(): void {
|
||||||
this.#content.get_child_at_index(0)?.get_child()?.activate();
|
this.#content.get_child_at_index(0)?.get_child()?.activate();
|
||||||
|
|
|
||||||
44
src/services/schemes.ts
Normal file
44
src/services/schemes.ts
Normal file
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue