[AGS] Launcher: Prepare

This commit is contained in:
Janis Hutz 2025-04-26 12:08:33 +02:00
parent 02861efcae
commit afe25a322a
4 changed files with 127 additions and 6 deletions

View File

@ -1,22 +1,23 @@
import { Variable } from "astal";
import { App, Astal, Gdk, Gtk } from "astal/gtk4";
import { App, Astal, Gdk, Gtk, hook } from "astal/gtk4";
import AstalApps from "gi://AstalApps";
import AppList from "./modules/Apps";
const MAX_ITEMS = 8;
const prefixes = ['='];
function hide() {
App.get_window("launcher")!.hide();
App.get_window("launcher")!.hide();
}
const Launcher = () => {
const { CENTER } = Gtk.Align;
const apps = new AstalApps.Apps();
const width = Variable(1000);
const height = Variable(1000);
const text = Variable("");
const visible = Variable(false);
const list = text((text) => apps.fuzzy_query(text).slice(0, MAX_ITEMS));
const onEnter = () => {
// TODO handle custom stuff
apps.fuzzy_query(text.get())?.[0].launch();
hide();
};
@ -29,13 +30,58 @@ const Launcher = () => {
application={App}
onShow={(self) => {
width.set(self.get_current_monitor().geometry.width);
height.set(self.get_current_monitor().geometry.height);
}}
onKeyPressed={(self, keyval) => {
if (keyval === Gdk.KEY_Escape) self.hide();
}}
child={
<box></box>
<box
vertical
cssClasses={["app-launcher-wrapper"]}
widthRequest={width()}
heightRequest={height()}
valign={Gtk.Align.CENTER}
>
<button onClicked={hide} visible={false} />
<box
vertical
cssClasses={["app-launcher"]}
valign={Gtk.Align.CENTER}
halign={Gtk.Align.CENTER}
widthRequest={500}
>
<button onClicked={hide} visible={false}></button>
<box cssClasses={["search"]}>
<image iconName={"system-search-symbolic"}></image>
<entry
placeholderText={"Search..."}
text={text.get()}
setup={self => {
hook(self, App, 'window-toggled', (_, win) => {
if (win.name == 'launcher') {
self.set_text('');
self.grab_focus();
}
})
}}
onNotifyText={self => text.set(self.text)}
primaryIconSensitive
onActivate={onEnter}
hexpand></entry>
</box>
<AppList
hide={hide}
query={text}
visible={text(v => {
return !prefixes.includes(v.slice(0, 1));
})}
></AppList>
</box>
</box>
}
>
</window>
}
export default Launcher;

View File

@ -0,0 +1,16 @@
@use '../../util/colours.scss' as *;
window {
background: transparent;
}
box.app-launcher-wrapper {
background-color: $shadow-color;
>box.app-launcher {
background-color: $bg-color;
border-radius: 30px;
padding: 20px;
border: 1px solid $accent-color-2;
}
}

View File

@ -0,0 +1,59 @@
import { Binding, Variable } from "astal";
import { Gtk } from "astal/gtk4";
import AstalApps from "gi://AstalApps";
import Pango from "gi://Pango?version=1.0";
const MAX_ITEMS = 8;
const AppList = ({ hide, query, visible }: { hide: () => void, query: Variable<string>, visible: Binding<Boolean> }) => {
const apps = new AstalApps.Apps();
const list = query((text) => apps.fuzzy_query(text).slice(0, MAX_ITEMS));
return <box>
<box
spacing={6}
vertical
cssClasses={["app-list"]}
visible={list.as(l => l.length > 0)}
>
{list.as(l => l.map(app => <AppButton app={app} hide={hide}></AppButton>))}
</box>
<box
halign={Gtk.Align.CENTER}
cssClasses={["list-empty"]}
vertical
visible={list.as(l => l.length === 0)}
>
<image iconName={"system-search-symbolic"}></image>
<label label={"No match found"}></label>
</box>
</box>
}
const AppButton = ({ app, hide }: { app: AstalApps.Application, hide: () => void }) => {
return <button
onClicked={() => {
hide();
app.launch();
}}
child={
<box>
<image iconName={app.iconName}></image>
<box valign={Gtk.Align.CENTER} vertical>
<label
cssClasses={["title-2"]}
ellipsize={Pango.EllipsizeMode.END}
maxWidthChars={40}
xalign={0}
label={app.name}
></label>
<label
wrap xalign={0}
label={app.description}
></label>
</box>
</box>
}>
</button>
}
export default AppList;