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:
Tetardtek-Cortex
2026-03-26 06:54:17 +01:00
parent 7e9d12e640
commit 932b174c36
30 changed files with 2557 additions and 0 deletions

View 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,
],
}),
});
};