60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
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;
|