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", css: "margin-left: 10px;" }), ], }), }) const AppLauncherWidget = ({ 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-image: url('https://images2.alphacoders.com/135/1351579.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: AppLauncherWidget({ width: 500, height: 500, spacing: 12, }), })