feat: Ghost Shell v2 — AGS v3 statusbar + violet-chaton v2 palette
- AGS v3.1.0 (Astal/GTK3) Ghost Shell avec ghost mode (heartbeat + hover reveal) - Modules : clock, battery, volume (interactif), network, MPRIS, CPU/RAM, systray - Brain Power panel (Super + B) — lecture live focus/todos/session - tetardtek_ prompt avec curseur clignotant - Palette violet-chaton v2 documentée (Mitsuri Kanroji gradient magenta → green) - Autostart COSMIC via .desktop - Archive AGS v1 conservée pour référence
This commit is contained in:
99
ags-v1/widgets/Launcher.js
Normal file
99
ags-v1/widgets/Launcher.js
Normal file
@@ -0,0 +1,99 @@
|
||||
// ── violet-chaton v2 — Launcher widget ──────────────────────────────────────
|
||||
// App launcher avec recherche fuzzy
|
||||
|
||||
const applications = Service.import("applications");
|
||||
|
||||
const AppItem = (app) => Widget.Button({
|
||||
className: "app-item",
|
||||
onClicked: () => {
|
||||
app.launch();
|
||||
App.closeWindow("launcher");
|
||||
},
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
Widget.Icon({ icon: app.iconName || "application-x-executable", size: 24 }),
|
||||
Widget.Box({
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Label({
|
||||
label: app.name,
|
||||
xalign: 0,
|
||||
truncate: "end",
|
||||
}),
|
||||
Widget.Label({
|
||||
label: app.description || "",
|
||||
xalign: 0,
|
||||
truncate: "end",
|
||||
className: "description",
|
||||
css: "color: #716686; font-size: 11px; font-weight: normal;",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
export const Launcher = (monitor) => {
|
||||
let apps = applications.list;
|
||||
|
||||
const list = Widget.Box({
|
||||
vertical: true,
|
||||
spacing: 2,
|
||||
});
|
||||
|
||||
const entry = Widget.Entry({
|
||||
className: "search",
|
||||
placeholderText: "Rechercher...",
|
||||
onAccept: () => {
|
||||
const first = apps[0];
|
||||
if (first) {
|
||||
first.launch();
|
||||
App.closeWindow("launcher");
|
||||
}
|
||||
},
|
||||
onChange: ({ text }) => {
|
||||
apps = applications.query(text || "");
|
||||
list.children = apps.slice(0, 12).map(AppItem);
|
||||
|
||||
if (apps.length === 0) {
|
||||
list.children = [Widget.Label({
|
||||
className: "no-results",
|
||||
label: "Aucun resultat",
|
||||
})];
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return Widget.Window({
|
||||
name: "launcher",
|
||||
monitor,
|
||||
anchor: ["top"],
|
||||
layer: "overlay",
|
||||
visible: false,
|
||||
keymode: "exclusive",
|
||||
setup: (self) => {
|
||||
self.keybind("Escape", () => App.closeWindow("launcher"));
|
||||
self.hook(App, (_, name, visible) => {
|
||||
if (name === "launcher" && visible) {
|
||||
entry.text = "";
|
||||
apps = applications.list;
|
||||
list.children = apps.slice(0, 12).map(AppItem);
|
||||
entry.grab_focus();
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Widget.Box({
|
||||
className: "launcher",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Scrollable({
|
||||
hscroll: "never",
|
||||
vscroll: "automatic",
|
||||
css: "min-height: 400px;",
|
||||
child: list,
|
||||
}),
|
||||
entry,
|
||||
],
|
||||
}),
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user