dotfiles/homes/me/ags/applauncher.js

125 lines
3 KiB
JavaScript

const { query } = await Service.import("applications");
const WINDOW_NAME = "applauncher";
const AppItem = app => Widget.Button({
on_clicked: () => {
App.closeWindow(WINDOW_NAME)
app.launch()
},
attribute: { app },
child: Widget.Box({
children: [
Widget.Icon({
icon: app.icon_name || "",
size: 42,
}),
Widget.Label({
class_name: "title",
label: app.name,
xalign: 0,
vpack: "center",
truncate: "end",
}),
],
}),
})
const AppLauncher = ({ width = 500, height = 500, spacing = 12 }) => {
let applications = query("").map(AppItem)
const list = Widget.Box({
vertical: true,
children: applications,
spacing,
})
function refresh() {
applications = query("").map(AppItem)
list.children = applications
}
const entry = Widget.Entry({
placeholder_text: "Search",
hexpand: true,
css: "min-height: 50px;",
// launch first item when Enter is pressed
on_accept: () => {
// only consider applications that are visible in the list
const results = applications.filter((item) => item.visible);
if (results[0]) {
App.toggleWindow(WINDOW_NAME);
results[0].attribute.app.launch()
}
},
// filter the applications based on search term
on_change: ({ text }) => applications.forEach(item => {
item.visible = item.attribute.app.match(text ?? "")
}),
})
return Widget.Box({
vertical: false,
children: [
// LEFT
Widget.Box({
vertical: true,
css: `min-width: ${width}px;`
+ `min-height: ${height}px;`
+ "background-color: #947BF5;",
//+ "background-image: url('../../../wallpaper/kill-my-firstborn/astronaut-pink-blue.png');",
//+ "background-size: cover;"
//+ "background-position: center;"
//+ "background-repeat: no-repeat;",
children: [
// align the entry field with the app list
Widget.Box({
css: `margin: ${spacing * 2}px;`,
child: entry,
}),
],
}),
// RIGHT
Widget.Box({
vertical: true,
css: `margin: ${spacing * 2}px;`,
child:
// make scrollable
Widget.Scrollable({
hscroll: "never",
css: `min-width: ${width}px; min-height: ${height}px;`,
child: list,
}),
setup: self => self.hook(App, (_, windowName, visible) => {
if (windowName !== WINDOW_NAME)
return
// when the launcher becomes visible
if (visible) {
refresh()
entry.text = ""
entry.grab_focus()
}
}),
}),
],
})
}
// the app launcher should be a singleton
export const applauncher = Widget.Window({
name: WINDOW_NAME,
setup: self => self.keybind("Escape", () => {
App.closeWindow(WINDOW_NAME)
}),
visible: false,
keymode: "exclusive",
child: AppLauncher({
width: 500,
height: 500,
spacing: 12,
}),
})