83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
import { Variable, bind } from "astal";
|
|
import { App, Astal, Gtk } from "astal/gtk4";
|
|
import { hideWindow } from "@lib/utils";
|
|
|
|
import Hyprland from "gi://AstalHyprland";
|
|
import Apps from "gi://AstalApps";
|
|
|
|
const hide = () => App.get_window("launcher")?.hide();
|
|
|
|
function AppButton({ app }: { app: Apps.Application }) {
|
|
return <button
|
|
cssClasses={["application"]}
|
|
onClicked={() => {
|
|
hide();
|
|
app.launch();
|
|
}}
|
|
>
|
|
<box>
|
|
<image iconName={app.iconName} />
|
|
<box valign={Gtk.Align.CENTER} vertical>
|
|
<label
|
|
cssClasses={["name"]}
|
|
xalign={0}
|
|
label={app.name}
|
|
/>
|
|
{app.description && <label
|
|
cssClasses={["description"]}
|
|
wrap
|
|
xalign={0}
|
|
label={app.description}
|
|
/>}
|
|
</box>
|
|
</box>
|
|
</button>
|
|
}
|
|
|
|
export default function Launcher(_monitor_id: number) {
|
|
const { TOP, BOTTOM, LEFT, RIGHT } = Astal.WindowAnchor;
|
|
|
|
const hypr = Hyprland.get_default();
|
|
const apps = new Apps.Apps();
|
|
|
|
const query = Variable("")
|
|
const list = query(text => apps.fuzzy_query(text).slice(0, 10))
|
|
const onEnter = () => {
|
|
hide()
|
|
list.get().at(0)!.launch()
|
|
}
|
|
|
|
return <window
|
|
visible={false}
|
|
monitor={bind(hypr, "focusedMonitor").as(monitor => monitor.id)}
|
|
name={"launcher"}
|
|
cssClasses={["launcher"]}
|
|
keymode={Astal.Keymode.EXCLUSIVE}
|
|
anchor={TOP | BOTTOM | LEFT | RIGHT}
|
|
onKeyPressed={hideWindow}
|
|
application={App}>
|
|
<box hexpand={false} vertical halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER}>
|
|
<box cssClasses={["launcher"]} vertical>
|
|
<entry
|
|
placeholderText="Search"
|
|
onChanged={self => query.set(self.text)}
|
|
onActivate={onEnter}
|
|
/>
|
|
<box spacing={6} vertical>
|
|
{list.as(list => list.map(app => (
|
|
<AppButton app={app} />
|
|
)))}
|
|
</box>
|
|
<box
|
|
halign={Gtk.Align.CENTER}
|
|
cssClasses={["not-found"]}
|
|
vertical
|
|
visible={list.as(l => l.length === 0)}>
|
|
<image iconName="system-search-symbolic" />
|
|
<label label="No match found" />
|
|
</box>
|
|
</box>
|
|
</box>
|
|
</window>
|
|
}
|