// ── violet-chaton v2 — Notifications widget ───────────────────────────────── // Popup notifications stylees — urgency-aware const notifications = await Service.import("notifications"); // Ne pas déranger notifications.popupTimeout = 5000; notifications.cacheActions = true; const NotificationIcon = (notif) => { if (notif.image) { return Widget.Box({ css: ` min-width: 48px; min-height: 48px; background-image: url("${notif.image}"); background-size: cover; background-position: center; border-radius: 8px; margin-right: 10px; `, }); } return Widget.Icon({ icon: notif.appIcon || notif.appEntry || "dialog-information", size: 36, css: "margin-right: 10px;", }); }; const Notification = (notif) => Widget.Box({ className: `notification ${notif.urgency}`, vertical: true, children: [ Widget.Box({ children: [ NotificationIcon(notif), Widget.Box({ vertical: true, hexpand: true, children: [ Widget.Box({ children: [ Widget.Label({ className: "title", label: notif.summary, xalign: 0, hexpand: true, truncate: "end", }), Widget.Label({ className: "time", label: new Date(notif.time * 1000) .toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit", }), }), Widget.Button({ className: "close-btn", label: "✕", onClicked: () => notif.close(), }), ], }), Widget.Label({ className: "app-name", label: notif.appName || "", xalign: 0, }), ], }), ], }), ...(notif.body ? [Widget.Label({ className: "body", label: notif.body, xalign: 0, wrap: true, useMarkup: true, })] : []), ...(notif.actions.length > 0 ? [Widget.Box({ className: "actions", children: notif.actions.map((action) => Widget.Button({ label: action.label, onClicked: () => notif.invoke(action.id), }) ), })] : []), ], }); export const Notifications = (monitor) => Widget.Window({ name: `notifications-${monitor}`, monitor, anchor: ["top", "right"], layer: "overlay", child: Widget.Box({ vertical: true, css: "min-width: 350px;", children: notifications.bind("popups").transform((popups) => popups.map(Notification) ), }), });