125 lines
3 KiB
JavaScript
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,
|
|
}),
|
|
})
|